From 48954bbd29f9a481ea368d6063e88d39417a2207 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Sun, 3 Jul 2016 12:45:16 +0300 Subject: [PATCH 01/50] testDiscovery for TestNG: apply chosen state --- .../testng/model/TestNGConfigurationModel.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/testng/src/com/theoryinpractice/testng/model/TestNGConfigurationModel.java b/plugins/testng/src/com/theoryinpractice/testng/model/TestNGConfigurationModel.java index db6076395e01..6053686d2f13 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/model/TestNGConfigurationModel.java +++ b/plugins/testng/src/com/theoryinpractice/testng/model/TestNGConfigurationModel.java @@ -112,11 +112,11 @@ public class TestNGConfigurationModel data.MAIN_CLASS_NAME = ""; data.METHOD_NAME = ""; data.SUITE_NAME = ""; - } else if (TestType.METHOD == type || TestType.CLASS == type) { + } else if (TestType.METHOD == type || TestType.CLASS == type || TestType.SOURCE == type) { String className = getText(TestType.CLASS); data.GROUP_NAME = ""; data.SUITE_NAME = ""; - if (TestType.METHOD == type) + if (TestType.METHOD == type || TestType.SOURCE == type) data.METHOD_NAME = getText(TestType.METHOD); PsiClass psiClass = !getProject().isDefault() && !StringUtil.isEmptyOrSpaces(className) ? JUnitUtil.findPsiClass(className, module, getProject()) : null; From 33273be517a101d87b074b788f7eac1e5398a141 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 4 Jul 2016 10:19:49 +0300 Subject: [PATCH 02/50] substitute with bounds promotion: don't open captured wildcard for supers (IDEA-155370) --- .../intellij/psi/impl/PsiSubstitutorImpl.java | 20 ++++++------------- .../BoundsPromotionWithCapturedWildcards.java | 13 ++++++++++++ .../LightAdvHighlightingFixtureTest.java | 8 ++++++++ 3 files changed, 27 insertions(+), 14 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advFixture/BoundsPromotionWithCapturedWildcards.java diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/PsiSubstitutorImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/PsiSubstitutorImpl.java index ebe896f1d844..29cc8832feb7 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/PsiSubstitutorImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/PsiSubstitutorImpl.java @@ -117,22 +117,14 @@ public class PsiSubstitutorImpl implements PsiSubstitutor { if (glb instanceof PsiWildcardType) { return glb; } - if (glb != null ) { - return glb instanceof PsiCapturedWildcardType ? ((PsiCapturedWildcardType)glb).getWildcard() - : PsiWildcardType.createExtends(typeParameter.getManager(), glb); + if (glb instanceof PsiCapturedWildcardType) { + PsiWildcardType wildcard = ((PsiCapturedWildcardType)glb).getWildcard(); + if (!wildcard.isSuper()) return wildcard; } - /* - if (glb instanceof PsiCapturedWildcardType) { - PsiWildcardType wildcard = ((PsiCapturedWildcardType)glb).getWildcard(); - if (!wildcard.isSuper()) return wildcard; - } - - if (glb != null ) { - return PsiWildcardType.createExtends(typeParameter.getManager(), glb); - } - */ - + if (glb != null) { + return PsiWildcardType.createExtends(typeParameter.getManager(), glb); + } } return substituted; } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advFixture/BoundsPromotionWithCapturedWildcards.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advFixture/BoundsPromotionWithCapturedWildcards.java new file mode 100644 index 000000000000..018b0bcbcd73 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advFixture/BoundsPromotionWithCapturedWildcards.java @@ -0,0 +1,13 @@ +import a.Provider; + +public abstract class Test { + private void configure(Provider provider, + Test sBind, + Test eBind) { + sBind.toProvider(provider); + eBind.toProvider(provider) + } + + abstract void toProvider(Provider var1); + abstract void toProvider(b.Provider var1); +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingFixtureTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingFixtureTest.java index ec4dac578f33..cae71202d460 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingFixtureTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingFixtureTest.java @@ -47,6 +47,14 @@ public class LightAdvHighlightingFixtureTest extends LightCodeInsightFixtureTest assertNull(ReferencesSearch.search(aClass).findFirst()); } + public void testBoundsPromotionWithCapturedWildcards() throws Exception { + myFixture.addClass("package a; public interface Provider {}"); + myFixture.addClass("package b; public interface Provider {}"); + + myFixture.configureByFile(getTestName(false) + ".java"); + myFixture.checkHighlighting(); + } + @Override protected String getBasePath() { return JavaTestUtil.getRelativeJavaTestDataPath() + "/codeInsight/daemonCodeAnalyzer/advFixture"; From af05034f6e4711da3a5cc74d3e750b967a76c49a Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 4 Jul 2016 10:34:50 +0200 Subject: [PATCH 03/50] a more compact storage for stub hierarchy names --- .../psi/stubsHierarchy/impl/Imports.java | 10 +-- .../stubsHierarchy/impl/NameEnvironment.java | 89 +++++++++++-------- .../stubsHierarchy/impl/NamesEnumerator.java | 70 --------------- .../stubsHierarchy/impl/QualifiedName.java | 20 +---- .../impl/SingleClassHierarchy.java | 2 +- .../psi/stubsHierarchy/impl/StubEnter.java | 28 +++--- .../impl/StubHierarchyConnector.java | 4 +- .../psi/stubsHierarchy/impl/StubResolver.java | 86 +++++++++--------- .../psi/stubsHierarchy/impl/Symbol.java | 6 +- .../psi/stubsHierarchy/impl/Symbols.java | 32 +++---- .../psi/stubsHierarchy/impl/Translator.java | 18 ++-- .../{CompactArray.java => annotations.java} | 23 ++++- 12 files changed, 161 insertions(+), 227 deletions(-) delete mode 100644 java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/NamesEnumerator.java rename java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/{CompactArray.java => annotations.java} (68%) diff --git a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Imports.java b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Imports.java index c5b45aa8287f..2b1ece3f88a8 100644 --- a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Imports.java +++ b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Imports.java @@ -30,11 +30,7 @@ public class Imports { return (int)(importMask >>> 32); } - public static QualifiedName getFullName(long importMask, NameEnvironment nameEnvironment) { - return nameEnvironment.qualifiedName(getFullNameId(importMask)); - } - - private static int getFullNameId(long importMask) { + static int getFullNameId(long importMask) { int fullNameId = (int)importMask; fullNameId &= mask; return fullNameId; @@ -48,8 +44,8 @@ public class Imports { return BitUtil.isSet(importMask, staticMask); } - public static long mkImport(QualifiedName fullname, boolean importStatic, boolean onDemand, int alias) { - long lower = fullname.myId; + public static long mkImport(@QNameId int fullname, boolean importStatic, boolean onDemand, int alias) { + long lower = fullname; if (importStatic) lower |= staticMask; if (onDemand) lower |= onDemandMask; return (((long)alias) << 32) | lower; diff --git a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/NameEnvironment.java b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/NameEnvironment.java index 4a2d5f3402a9..2c9db64a54c9 100644 --- a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/NameEnvironment.java +++ b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/NameEnvironment.java @@ -16,60 +16,71 @@ package com.intellij.psi.stubsHierarchy.impl; import com.intellij.openapi.util.UserDataHolderBase; +import com.intellij.psi.CommonClassNames; import com.intellij.psi.impl.java.stubs.hierarchy.IndexTree; -import org.jetbrains.annotations.Nullable; +import gnu.trove.TIntArrayList; +import gnu.trove.TLongIntHashMap; -import java.util.Arrays; - -public class NameEnvironment extends UserDataHolderBase { +class NameEnvironment extends UserDataHolderBase { public static final int OBJECT_NAME = IndexTree.hashIdentifier("Object"); - public final QualifiedName empty; - public final QualifiedName java_lang; + public static final int NO_NAME = 0; + @QNameId public final int java_lang; public final QualifiedName java_lang_Enum; - public final QualifiedName annotation; - public final NamesEnumerator myNamesEnumerator; + public final QualifiedName java_lang_annotation_Annotation; - public NameEnvironment() { - myNamesEnumerator = new NamesEnumerator(); - empty = myNamesEnumerator.getFullName(new int[]{}, true); - java_lang = fromString("java.lang", true); - java_lang_Enum = fromString("java.lang.Enum", true); - annotation = fromString("java.lang.annotation.Annotation", true); + private final TIntArrayList mySuffixes = new TIntArrayList(); + private final TIntArrayList myStems = new TIntArrayList(); + private final TLongIntHashMap myConcatenations = new TLongIntHashMap(); + + NameEnvironment() { + mySuffixes.add(0); + myStems.add(0); + + java_lang = fromString("java.lang"); + java_lang_Enum = new QualifiedName(fromString(CommonClassNames.JAVA_LANG_ENUM)); + java_lang_annotation_Annotation = new QualifiedName(fromString(CommonClassNames.JAVA_LANG_ANNOTATION_ANNOTATION)); } - @Nullable - public QualifiedName fromString(String s, boolean create) { - return myNamesEnumerator.getFullName(IndexTree.hashQualifiedName(s), create); + @QNameId + int fromString(String s) { + return internQualifiedName(IndexTree.hashQualifiedName(s)); } - public QualifiedName prefix(QualifiedName name) { - if (name.myComponents.length <= 1) { - return empty; + @QNameId int prefixId(@QNameId int nameId) { + return myStems.get(nameId); + } + + @ShortName int shortName(@QNameId int id) { + return mySuffixes.get(id); + } + + @QNameId int findExistingName(@QNameId int stemId, @ShortName int suffix) { + int existing = myConcatenations.get(pack(stemId, suffix)); + return existing > 0 ? existing : -1; + } + + @QNameId int internQualifiedName(@ShortName int[] qname) { + int id = 0; + for (int shortName : qname) { + id = qualifiedName(id, shortName); } - return myNamesEnumerator.getFullName(Arrays.copyOf(name.myComponents, name.myComponents.length - 1), true); + return id; } - public QualifiedName qualifiedName(int id) { - return myNamesEnumerator.qualifiedName(id); + @QNameId int qualifiedName(@QNameId int prefix, @ShortName int shortName) { + int existing = findExistingName(prefix, shortName); + return existing >= 0 ? existing : addName(prefix, shortName); } - public int shortName(QualifiedName name) { - int[] ids = name.myComponents; - return ids[ids.length - 1]; + private int addName(@QNameId int stemId, @ShortName int suffix) { + int newId = mySuffixes.size(); + mySuffixes.add(suffix); + myStems.add(stemId); + myConcatenations.put(pack(stemId, suffix), newId); + return newId; } - public QualifiedName qualifiedName(QualifiedName prefix, int shortName, boolean create) { - if (shortName == NamesEnumerator.NO_NAME) - return null; - if (prefix == null || prefix.isEmpty()) - return myNamesEnumerator.getFullName(new int[]{shortName}, create); - - int[] ids = Arrays.copyOf(prefix.myComponents, prefix.myComponents.length + 1); - ids[ids.length - 1] = shortName; - return myNamesEnumerator.getFullName(ids, create); - } - - QualifiedName concat(int[] ids, boolean create) { - return myNamesEnumerator.getFullName(ids, create); + private static long pack(@QNameId int stemId, @ShortName int suffix) { + return ((long)suffix << 32) + stemId; } } diff --git a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/NamesEnumerator.java b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/NamesEnumerator.java deleted file mode 100644 index cde21cf6ca45..000000000000 --- a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/NamesEnumerator.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2000-2015 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * 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.psi.stubsHierarchy.impl; - -import gnu.trove.TObjectHashingStrategy; -import gnu.trove.TObjectIntHashMap; - -import java.util.Arrays; - -public class NamesEnumerator { - final static int NO_NAME = 0; - - private final TObjectIntHashMap myFullNameMap = new TObjectIntHashMap(new TObjectHashingStrategy() { - @Override - public int computeHashCode(int[] object) { - return Arrays.hashCode(object); - } - - @Override - public boolean equals(int[] o1, int[] o2) { - return Arrays.equals(o1, o2); - } - }); - private QualifiedName[] myQualifiedNames = new QualifiedName[0x8000]; - - QualifiedName qualifiedName(int id) { - return myQualifiedNames[id]; - } - - public QualifiedName getFullName(int[] ids, boolean create) { - int id = myFullNameMap.get(ids); - if (id == 0 && create) { - id = myFullNameMap.size() + 1; - myFullNameMap.put(ids, id); - ensureFullCapacity(id); - myQualifiedNames[id] = new QualifiedName(id, ids); - } - return myQualifiedNames[id]; - } - - - private void ensureFullCapacity(int maxIndex) { - if (maxIndex >= myQualifiedNames.length) { - int newLength = calculateNewLength(myQualifiedNames.length, maxIndex); - QualifiedName[] names1 = new QualifiedName[newLength]; - System.arraycopy(myQualifiedNames, 0, names1, 0, myQualifiedNames.length); - myQualifiedNames = names1; - } - } - - private static int calculateNewLength(int currentLength, int maxIndex) { - while (currentLength < maxIndex + 1) - currentLength *= 2; - return currentLength; - } - -} diff --git a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/QualifiedName.java b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/QualifiedName.java index 2756a2edfebb..575bb59f7b8c 100644 --- a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/QualifiedName.java +++ b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/QualifiedName.java @@ -15,33 +15,21 @@ */ package com.intellij.psi.stubsHierarchy.impl; -import java.util.Arrays; - -public final class QualifiedName { - public static final QualifiedName[] EMPTY_ARRAY = new QualifiedName[0]; - - // unique id of this full name +final class QualifiedName { public final int myId; - // ids of parts of this name - public final int[] myComponents; - QualifiedName(int id, int[] components) { + QualifiedName(int id) { this.myId = id; - this.myComponents = components; } public boolean isEmpty() { - return myComponents.length == 0; + return myId == 0; } @Override public boolean equals(Object o) { if (this == o) return true; - if (o instanceof QualifiedName) { - QualifiedName other = (QualifiedName)o; - return myId == other.myId && Arrays.equals(myComponents, other.myComponents); - } - return false; + return o instanceof QualifiedName && myId == ((QualifiedName)o).myId; } @Override diff --git a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/SingleClassHierarchy.java b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/SingleClassHierarchy.java index 982b1af46211..e148321511fb 100644 --- a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/SingleClassHierarchy.java +++ b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/SingleClassHierarchy.java @@ -71,7 +71,7 @@ public class SingleClassHierarchy extends ClassHierarchy { private static BitSet calcAnonymous(ClassSymbol[] classSymbols) { BitSet answer = new BitSet(); for (ClassSymbol symbol : classSymbols) { - if (!symbol.isHierarchyIncomplete() && symbol.myShortName == NamesEnumerator.NO_NAME) { + if (!symbol.isHierarchyIncomplete() && symbol.myShortName == NameEnvironment.NO_NAME) { answer.set(symbol.myAnchorId); } } diff --git a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/StubEnter.java b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/StubEnter.java index 9dd9c22425b9..0bc428733c76 100644 --- a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/StubEnter.java +++ b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/StubEnter.java @@ -38,10 +38,8 @@ public class StubEnter { } void unitEnter(IndexTree.Unit unit, int fileId) { - PackageSymbol pkg = unit.myPackageName.length > 0 - ? mySymbols.enterPackage(myNameEnvironment.myNamesEnumerator.getFullName(unit.myPackageName, true)) - : mySymbols.myRootPackage; - enter(unit.myDecls, UnitInfo.mkUnitInfo(unit.myUnitType, internImports(unit)), pkg, pkg.myQualifiedName, fileId); + @QNameId int pkgName = unit.myPackageName.length > 0 ? myNameEnvironment.internQualifiedName(unit.myPackageName) : 0; + enter(unit.myDecls, UnitInfo.mkUnitInfo(unit.myUnitType, internImports(unit)), mySymbols.enterPackage(pkgName), pkgName, fileId); } private long[] internImports(IndexTree.Unit unit) { @@ -53,17 +51,17 @@ public class StubEnter { } private long processImport(IndexTree.Import anImport) { - QualifiedName fullname = myNameEnvironment.myNamesEnumerator.getFullName(anImport.myFullname, true); + int fullname = myNameEnvironment.internQualifiedName(anImport.myFullname); return Imports.mkImport(fullname, anImport.myStaticImport, anImport.myOnDemand, anImport.myAlias); } - private void enter(IndexTree.ClassDecl[] trees, UnitInfo info, Symbol owner, @Nullable QualifiedName ownerName, int fileId) { + private void enter(IndexTree.ClassDecl[] trees, UnitInfo info, Symbol owner, @QNameId int ownerName, int fileId) { for (IndexTree.ClassDecl tree : trees) { enter(tree, info, owner, ownerName, fileId); } } - private ClassSymbol[] enter(IndexTree.Decl[] trees, UnitInfo info, Symbol owner, @Nullable QualifiedName ownerName, int fileId) { + private ClassSymbol[] enter(IndexTree.Decl[] trees, UnitInfo info, Symbol owner, @QNameId int ownerName, int fileId) { ClassSymbol[] members = new ClassSymbol[trees.length]; int i = 0; for (IndexTree.Decl tree : trees) { @@ -81,7 +79,7 @@ public class StubEnter { return members; } - private ClassSymbol enter(IndexTree.Decl tree, UnitInfo info, Symbol owner, QualifiedName ownerName, int fileId) { + private ClassSymbol enter(IndexTree.Decl tree, UnitInfo info, Symbol owner, @QNameId int ownerName, int fileId) { if (tree instanceof IndexTree.ClassDecl) { return classEnter((IndexTree.ClassDecl)tree, info, owner, ownerName, fileId); } @@ -92,20 +90,20 @@ public class StubEnter { return null; } - private void memberEnter(IndexTree.MemberDecl tree, UnitInfo info, Symbol owner, @Nullable QualifiedName ownerName, int fileId) { + private void memberEnter(IndexTree.MemberDecl tree, UnitInfo info, Symbol owner, @QNameId int ownerName, int fileId) { MemberSymbol mc = new MemberSymbol(owner); mc.setMembers(enter(tree.myDecls, info, mc, ownerName, fileId)); } - private ClassSymbol classEnter(IndexTree.ClassDecl tree, UnitInfo info, Symbol owner, @Nullable QualifiedName ownerName, int fileId) { + private ClassSymbol classEnter(IndexTree.ClassDecl tree, UnitInfo info, Symbol owner, @QNameId int ownerName, int fileId) { int flags = checkFlags(tree.myMods, owner); if (info.getType() == IndexTree.BYTECODE) { flags |= IndexTree.COMPILED; } int name = tree.myName; - QualifiedName qname = name == NamesEnumerator.NO_NAME || ownerName == null ? null - : myNameEnvironment.qualifiedName(ownerName, name, true); + @QNameId int qname = name == NameEnvironment.NO_NAME || ownerName < 0 ? -1 + : myNameEnvironment.qualifiedName(ownerName, name); @CompactArray(QualifiedName.class) Object supers = internSupers(tree.myMods, tree.mySupers); ClassSymbol classSymbol = mySymbols.enterClass(fileId, tree.myStubId, flags, name, owner, info, supers, qname); @@ -122,7 +120,7 @@ public class StubEnter { @CompactArray(QualifiedName.class) private Object internSupers(int flags, int[][] superNames) { if (BitUtil.isSet(flags, IndexTree.ANNOTATION)) { - return myNameEnvironment.annotation; + return myNameEnvironment.java_lang_annotation_Annotation; } boolean isEnum = BitUtil.isSet(flags, IndexTree.ENUM); @@ -130,12 +128,12 @@ public class StubEnter { return isEnum ? myNameEnvironment.java_lang_Enum : null; } if (superNames.length == 1 && !isEnum) { - return myNameEnvironment.concat(superNames[0], true); + return new QualifiedName(myNameEnvironment.internQualifiedName(superNames[0])); } QualifiedName[] array = new QualifiedName[superNames.length + (isEnum ? 1 : 0)]; for (int i = 0; i < superNames.length; i++) { - array[i] = myNameEnvironment.concat(superNames[i], true); + array[i] = new QualifiedName(myNameEnvironment.internQualifiedName(superNames[i])); } if (isEnum) { array[array.length - 1] = myNameEnvironment.java_lang_Enum; diff --git a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/StubHierarchyConnector.java b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/StubHierarchyConnector.java index 597ab6ab929c..2373dcc3a28f 100644 --- a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/StubHierarchyConnector.java +++ b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/StubHierarchyConnector.java @@ -31,14 +31,14 @@ public class StubHierarchyConnector { private void resolveName(Symbol.ClassSymbol place, QualifiedName name, Set result) throws IncompleteHierarchyException { if (place.isCompiled()) { - Symbol.ClassSymbol[] candidates = myResolve.findGlobalType(name); + Symbol.ClassSymbol[] candidates = myResolve.findGlobalType(name.myId); if (candidates.length == 0) { throw new IncompleteHierarchyException(); } Collections.addAll(result, candidates); } else { - for (Symbol symbol : myResolve.resolveBase(place, name.myComponents)) { + for (Symbol symbol : myResolve.resolveBase(place, name.myId, false)) { if (symbol instanceof Symbol.ClassSymbol) { result.add((Symbol.ClassSymbol)symbol); } diff --git a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/StubResolver.java b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/StubResolver.java index d8791ff8a2ea..5d35b4210bfd 100644 --- a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/StubResolver.java +++ b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/StubResolver.java @@ -17,6 +17,7 @@ package com.intellij.psi.stubsHierarchy.impl; import com.intellij.psi.impl.java.stubs.hierarchy.IndexTree; import com.intellij.util.BitUtil; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -36,16 +37,22 @@ public class StubResolver { } // resolve class `sym` extends/implements `baseId` - Set resolveBase(Symbol.ClassSymbol sym, int[] baseId) throws IncompleteHierarchyException { - Set result = findIdent(sym.myOwner, sym.myUnitInfo, baseId[0], baseId.length > 1); - for (int i = 1; i < baseId.length; i++) { - Set prev = result; - int k = (i == baseId.length - 1) ? IndexTree.CLASS : IndexTree.CLASS | IndexTree.PACKAGE; - - result = new HashSet<>(); - for (Symbol symbol : prev) { - selectSym(symbol, baseId[i], k, result); + Set resolveBase(Symbol.ClassSymbol sym, @QNameId int name, boolean processPackages) throws IncompleteHierarchyException { + @QNameId int prefix = myNameEnvironment.prefixId(name); + @ShortName int shortName = myNameEnvironment.shortName(name); + if (prefix == NameEnvironment.NO_NAME) { + Set result = findIdent(sym.myOwner, sym.myUnitInfo, shortName, processPackages); + if (result.isEmpty()) { + throw IncompleteHierarchyException.INSTANCE; } + return result; + } + + int k = processPackages ? IndexTree.CLASS | IndexTree.PACKAGE : IndexTree.CLASS; + Set prev = resolveBase(sym, prefix, true); + Set result = new HashSet<>(); + for (Symbol symbol : prev) { + selectSym(symbol, shortName, k, result); } if (result.isEmpty()) { throw IncompleteHierarchyException.INSTANCE; @@ -54,15 +61,15 @@ public class StubResolver { } @NotNull - private Set findIdent(Symbol startScope, UnitInfo info, int name, boolean processPackages) throws IncompleteHierarchyException { + private Set findIdent(Symbol startScope, UnitInfo info, @ShortName int name, boolean processPackages) throws IncompleteHierarchyException { Set result = new HashSet(); findType(startScope, name, result); findGlobalType(info, name, result); if (processPackages) { - Symbol.PackageSymbol pkg = mySymbols.getPackage(myNameEnvironment.qualifiedName(null, name, false)); - if (pkg != null) - result.add(pkg); + @QNameId int nameId = myNameEnvironment.findExistingName(0, name); + Symbol.PackageSymbol pkg = nameId < 0 ? null : mySymbols.getPackage(nameId); + ContainerUtil.addIfNotNull(result, pkg); } return result; } @@ -76,16 +83,16 @@ public class StubResolver { } // resolving `receiver.name` - private void selectSym(Symbol receiver, int name, int kind, Set symbols) throws IncompleteHierarchyException { + private void selectSym(Symbol receiver, @ShortName int name, int kind, Set symbols) throws IncompleteHierarchyException { if (receiver.isPackage()) findIdentInPackage((Symbol.PackageSymbol)receiver, name, kind, symbols); else findMemberType(receiver, name, symbols); } - private void findIdentInPackage(Symbol.PackageSymbol pck, int name, int kind, Set symbols) { - QualifiedName fullname = mySymbols.myNameEnvironment.qualifiedName(pck.myQualifiedName, name, false); - if (fullname == null) { + private void findIdentInPackage(Symbol.PackageSymbol pck, @ShortName int name, int kind, Set symbols) { + @QNameId int fullname = mySymbols.myNameEnvironment.findExistingName(pck.myQualifiedName, name); + if (fullname < 0) { return; } if (BitUtil.isSet(kind, IndexTree.PACKAGE)) { @@ -94,11 +101,11 @@ public class StubResolver { symbols.add(pkg); } if (BitUtil.isSet(kind, IndexTree.CLASS)) { - Collections.addAll(symbols, loadClass(fullname)); + Collections.addAll(symbols, findGlobalType(fullname)); } } - private void findMemberType(Symbol s, int name, Set symbols) throws IncompleteHierarchyException { + private void findMemberType(Symbol s, @ShortName int name, Set symbols) throws IncompleteHierarchyException { if (s.isClass()) { processInheritedMembers((Symbol.ClassSymbol)s, name, false, symbols, null); } else { @@ -107,7 +114,7 @@ public class StubResolver { } private void processInheritedMembers(Symbol.ClassSymbol s, - int name, + @ShortName int name, boolean requireStatic, Set symbols, @Nullable Set processed) throws IncompleteHierarchyException { @@ -128,23 +135,19 @@ public class StubResolver { } } - private Symbol.ClassSymbol[] loadClass(@NotNull QualifiedName fqn) { - return mySymbols.loadClass(fqn); + public Symbol.ClassSymbol[] findGlobalType(@QNameId int nameId) { + return mySymbols.loadClass(nameId); } - public Symbol.ClassSymbol[] findGlobalType(@NotNull QualifiedName name) { - return loadClass(name); - } - - private void findGlobalType(UnitInfo info, int name, Set symbols) throws IncompleteHierarchyException { + private void findGlobalType(UnitInfo info, @ShortName int name, Set symbols) throws IncompleteHierarchyException { for (long anImport : Translator.getDefaultImports(info.getType(), myNameEnvironment)) handleImport(anImport, name, symbols); for (long anImport : info.getImports()) handleImport(anImport, name, symbols); } - public void handleImport(long tree, int name, Set symbols) throws IncompleteHierarchyException { - QualifiedName fullname = Imports.getFullName(tree, myNameEnvironment); + public void handleImport(long tree, @ShortName int name, Set symbols) throws IncompleteHierarchyException { + @QNameId int fullname = Imports.getFullNameId(tree); if (Imports.isOnDemand(tree)) { if (Imports.isStatic(tree)) { for (Symbol.ClassSymbol p : findGlobalType(fullname)) @@ -155,12 +158,12 @@ public class StubResolver { } } else { - QualifiedName prefix = myNameEnvironment.prefix(fullname); - if (prefix.isEmpty()) { + @QNameId int prefix = myNameEnvironment.prefixId(fullname); + if (prefix == 0) { return; } - int shortName = myNameEnvironment.shortName(fullname); - int alias = Imports.getAlias(tree); + @ShortName int shortName = myNameEnvironment.shortName(fullname); + @ShortName int alias = Imports.getAlias(tree); boolean shouldImport = ((alias & name) == name) || shortName == name; if (!shouldImport) return; @@ -175,22 +178,19 @@ public class StubResolver { } // handling of `import prefix.*` - private void importAll(@NotNull final QualifiedName prefix, int suffix, final Set symbols) { - - QualifiedName fullname = myNameEnvironment.qualifiedName(prefix, suffix, false); - // existing only - if (fullname != null) { - Symbol.ClassSymbol[] ss = findGlobalType(fullname); - Collections.addAll(symbols, ss); - } + private void importAll(@QNameId int prefix, @ShortName int suffix, final Set symbols) { + @QNameId int fullname = myNameEnvironment.findExistingName(prefix, suffix); + if (fullname >= 0) { + Collections.addAll(symbols, findGlobalType(fullname)); + } } // handling of import static `tsym.name` as - private void importNamedStatic(final Symbol.ClassSymbol tsym, final int name, final Set symbols) throws IncompleteHierarchyException { + private void importNamedStatic(final Symbol.ClassSymbol tsym, @ShortName final int name, final Set symbols) throws IncompleteHierarchyException { processInheritedMembers(tsym, name, true, symbols, null); } - private static void processMembers(Symbol.ClassSymbol[] members, int name, Set symbols, boolean requireStatic) { + private static void processMembers(Symbol.ClassSymbol[] members, @ShortName int name, Set symbols, boolean requireStatic) { int index = getIndex(name, members); if (index < 0) return; diff --git a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Symbol.java b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Symbol.java index 40ef829ae232..f996e7c5a489 100644 --- a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Symbol.java +++ b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Symbol.java @@ -74,9 +74,9 @@ public abstract class Symbol { } public static class PackageSymbol extends Symbol { - final QualifiedName myQualifiedName; + @QNameId final int myQualifiedName; - public PackageSymbol(Symbol owner, QualifiedName fullname, int name) { + public PackageSymbol(Symbol owner, @QNameId int fullname, int name) { super(IndexTree.PACKAGE, owner, name); myQualifiedName = fullname; } @@ -186,7 +186,7 @@ public abstract class Symbol { @CompactArray(ClassSymbol.class) private Object myMembers = null; MemberSymbol(Symbol owner) { - super(IndexTree.MEMBER, owner, NamesEnumerator.NO_NAME); + super(IndexTree.MEMBER, owner, NameEnvironment.NO_NAME); } MemberSymbol(int flags, Symbol owner, int name) { diff --git a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Symbols.java b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Symbols.java index f4ec857f5fc7..a81281adec67 100644 --- a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Symbols.java +++ b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Symbols.java @@ -21,35 +21,29 @@ public class Symbols { private Object[] myClassSymbolsByNameId = new Object[0x8000]; protected Symbols() { - myRootPackage = new PackageSymbol(null, myNameEnvironment.empty, NamesEnumerator.NO_NAME); - myPackages.put(myNameEnvironment.empty.myId, myRootPackage); + myRootPackage = new PackageSymbol(null, 0, NameEnvironment.NO_NAME); + myPackages.put(0, myRootPackage); } - public PackageSymbol enterPackage(QualifiedName qualifiedName) { - PackageSymbol p = myPackages.get(qualifiedName.myId); + public PackageSymbol enterPackage(@QNameId int qualifiedName) { + PackageSymbol p = myPackages.get(qualifiedName); if (p == null) { - PackageSymbol owner = enterPackage(myNameEnvironment.prefix(qualifiedName)); + PackageSymbol owner = enterPackage(myNameEnvironment.prefixId(qualifiedName)); int shortName = myNameEnvironment.shortName(qualifiedName); p = new PackageSymbol(owner, qualifiedName, shortName); - myPackages.put(qualifiedName.myId, p); + myPackages.put(qualifiedName, p); } return p; } @Nullable - public PackageSymbol getPackage(QualifiedName qualifiedName) { - if (qualifiedName == null) - return null; - return myPackages.get(qualifiedName.myId); + PackageSymbol getPackage(@QNameId int qualifiedName) { + return myPackages.get(qualifiedName); } @NotNull - public ClassSymbol[] loadClass(@NotNull QualifiedName qualifiedName) { - int i = qualifiedName.myId; - if (i >= myClassSymbolsByNameId.length) { - return ClassSymbol.EMPTY_ARRAY; - } - return getClassSymbols(i); + ClassSymbol[] loadClass(@QNameId int name) { + return name >= myClassSymbolsByNameId.length ? ClassSymbol.EMPTY_ARRAY : getClassSymbols(name); } private ClassSymbol[] getClassSymbols(int id) { @@ -70,12 +64,12 @@ public class Symbols { Symbol owner, UnitInfo info, @CompactArray(QualifiedName.class) Object supers, - @Nullable QualifiedName qualifiedName) { + @QNameId int qualifiedName) { int anchorId = myClassAnchors.registerClass(fileId, stubId); ClassSymbol c = new ClassSymbol(anchorId, flags, owner, shortName, info, supers); myClassSymbols.add(c); - if (qualifiedName != null) { - putClassByName(c, qualifiedName.myId); + if (qualifiedName >= 0) { + putClassByName(c, qualifiedName); } return c; } diff --git a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Translator.java b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Translator.java index 9baa9d08e2e0..c1e3fff734da 100644 --- a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Translator.java +++ b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Translator.java @@ -33,7 +33,7 @@ public class Translator { private static long[] createDefaultJavaImports(NameEnvironment nameEnvironment) { return new long[]{ - Imports.mkImport(nameEnvironment.fromString("java.lang", true), false, true, 0) + Imports.mkImport(nameEnvironment.fromString("java.lang"), false, true, 0) }; } @@ -48,14 +48,14 @@ public class Translator { private static long[] createDefaultGroovyImports(NameEnvironment nameEnvironment) { return new long[] { - Imports.mkImport(nameEnvironment.fromString("java.lang", true), false, true, 0), - Imports.mkImport(nameEnvironment.fromString("java.util", true), false, true, 0), - Imports.mkImport(nameEnvironment.fromString("java.io", true), false, true, 0), - Imports.mkImport(nameEnvironment.fromString("java.net", true), false, true, 0), - Imports.mkImport(nameEnvironment.fromString("groovy.lang", true), false, true, 0), - Imports.mkImport(nameEnvironment.fromString("groovy.util", true), false, true, 0), - Imports.mkImport(nameEnvironment.fromString("java.math.BigInteger", true), false, true, 0), - Imports.mkImport(nameEnvironment.fromString("java.math.BigDecimal", true), false, true, 0), + Imports.mkImport(nameEnvironment.fromString("java.lang"), false, true, 0), + Imports.mkImport(nameEnvironment.fromString("java.util"), false, true, 0), + Imports.mkImport(nameEnvironment.fromString("java.io"), false, true, 0), + Imports.mkImport(nameEnvironment.fromString("java.net"), false, true, 0), + Imports.mkImport(nameEnvironment.fromString("groovy.lang"), false, true, 0), + Imports.mkImport(nameEnvironment.fromString("groovy.util"), false, true, 0), + Imports.mkImport(nameEnvironment.fromString("java.math.BigInteger"), false, true, 0), + Imports.mkImport(nameEnvironment.fromString("java.math.BigDecimal"), false, true, 0), }; } diff --git a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/CompactArray.java b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/annotations.java similarity index 68% rename from java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/CompactArray.java rename to java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/annotations.java index 3ef96d52169c..0b7b09f32c50 100644 --- a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/CompactArray.java +++ b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/annotations.java @@ -15,8 +15,12 @@ */ package com.intellij.psi.stubsHierarchy.impl; +import com.intellij.psi.impl.java.stubs.hierarchy.IndexTree; + +import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; /** * This annotation exists for documentation purposes only.

@@ -24,10 +28,23 @@ import java.lang.annotation.RetentionPolicy; * The value annotated with this annotation is used to save memory when storing mostly-singular or empty collections. * For empty collection, 'null' value is used. For one-element collection, the value is the single element. Otherwise, * an array is used. Possible component types are specified in the annotation value. - * - * @author peter */ @Retention(RetentionPolicy.SOURCE) -public @interface CompactArray { +@Target(ElementType.TYPE_USE) +@interface CompactArray { Class[] value(); } + +/** + * int id of a qualified name in a {@link NameEnvironment} + */ +@Retention(RetentionPolicy.SOURCE) +@Target(ElementType.TYPE_USE) +@interface QNameId { } + +/** + * int hash of a qualified name part, produced by {@link IndexTree#hashIdentifier(String)} + */ +@Retention(RetentionPolicy.SOURCE) +@Target(ElementType.TYPE_USE) +@interface ShortName { } From d02d25f9d96e10929290329c6db56c1fcca49bf4 Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Mon, 4 Jul 2016 11:44:48 +0300 Subject: [PATCH 04/50] EA-84907 - NPE: ClassFilterEditor$FilterTableModel.getValueAt --- .../debugger/ui/InstanceFilterEditor.java | 43 +++++++++++++------ 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/InstanceFilterEditor.java b/java/debugger/impl/src/com/intellij/debugger/ui/InstanceFilterEditor.java index 2af4adccbb70..b4ea92616d3f 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/InstanceFilterEditor.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/InstanceFilterEditor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,10 +17,12 @@ package com.intellij.debugger.ui; import com.intellij.debugger.DebuggerBundle; import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.InputValidatorEx; import com.intellij.openapi.ui.Messages; import com.intellij.ui.classFilter.ClassFilter; import com.intellij.ui.classFilter.ClassFilterEditor; import com.intellij.util.IconUtil; +import org.jetbrains.annotations.Nullable; import javax.swing.*; @@ -35,7 +37,34 @@ public class InstanceFilterEditor extends ClassFilterEditor { } protected void addClassFilter() { - String idString = Messages.showInputDialog(myProject, DebuggerBundle.message("add.instance.filter.dialog.prompt"), DebuggerBundle.message("add.instance.filter.dialog.title"), Messages.getQuestionIcon()); + String idString = Messages.showInputDialog(myProject, + DebuggerBundle.message("add.instance.filter.dialog.prompt"), + DebuggerBundle.message("add.instance.filter.dialog.title"), + Messages.getQuestionIcon(), + null, + new InputValidatorEx() { + @Nullable + @Override + public String getErrorText(String inputString) { + try { + //noinspection ResultOfMethodCallIgnored + Long.parseLong(inputString); + return null; + } catch (NumberFormatException e) { + return DebuggerBundle.message("add.instance.filter.dialog.error.numeric.value.expected"); + } + } + + @Override + public boolean checkInput(String inputString) { + return getErrorText(inputString) == null; + } + + @Override + public boolean canClose(String inputString) { + return getErrorText(inputString) == null; + } + }); if (idString != null) { ClassFilter filter = createFilter(idString); myTableModel.addRow(filter); @@ -60,14 +89,4 @@ public class InstanceFilterEditor extends ClassFilterEditor { protected boolean addPatternButtonVisible() { return false; } - - protected ClassFilter createFilter(String pattern) { - try { - Long.parseLong(pattern); - return super.createFilter(pattern); - } catch (NumberFormatException e) { - Messages.showMessageDialog(this, DebuggerBundle.message("add.instance.filter.dialog.error.numeric.value.expected"), DebuggerBundle.message("add.instance.filter.dialog.title"), Messages.getErrorIcon()); - return null; - } - } } From 311e83d5c7a71aeba8a3aefe88913df8241e98d5 Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Mon, 4 Jul 2016 12:07:17 +0300 Subject: [PATCH 05/50] EA-85173 - assert: ComponentManagerImpl.getPicoContainer --- .../src/com/intellij/xdebugger/impl/XDebugSessionImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java index de0ae90c6aa6..ca1e01fd3a54 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java @@ -775,7 +775,7 @@ public class XDebugSessionImpl implements XDebugSession { updateExecutionPosition(); if (myShowTabOnSuspend.compareAndSet(true, false)) { - UIUtil.invokeLaterIfNeeded(() -> { + AppUIUtil.invokeLaterIfProjectAlive(myProject, () -> { initSessionTab(null); showSessionTab(); }); From beff9782a80af51eff695c40ee978f6e92dd323d Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Mon, 4 Jul 2016 12:25:53 +0300 Subject: [PATCH 06/50] Cleanup (minor optimization) --- .../openapi/components/impl/stores/StoreUtil.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StoreUtil.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StoreUtil.java index 4fd37486ca51..623b1bb889ce 100644 --- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StoreUtil.java +++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StoreUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -40,11 +40,11 @@ import org.jetbrains.annotations.Nullable; public final class StoreUtil { private static final Logger LOG = Logger.getInstance(StoreUtil.class); - private StoreUtil() { - } + private StoreUtil() { } public static void save(@NotNull IComponentStore stateStore, @Nullable Project project) { - ShutDownTracker.getInstance().registerStopperThread(Thread.currentThread()); + Thread currentThread = Thread.currentThread(); + ShutDownTracker.getInstance().registerStopperThread(currentThread); try { stateStore.save(new SmartList>()); } @@ -77,7 +77,7 @@ public final class StoreUtil { } } finally { - ShutDownTracker.getInstance().unregisterStopperThread(Thread.currentThread()); + ShutDownTracker.getInstance().unregisterStopperThread(currentThread); } } From eae5c9a98896fd395a8ea6c87fb6503359a97b40 Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Mon, 4 Jul 2016 12:39:50 +0300 Subject: [PATCH 07/50] filled all needed fields in class structure to fix NPEs from ASM parser --- .../debugger/jdi/MethodBytecodeUtil.java | 66 ++++++++++++------- 1 file changed, 44 insertions(+), 22 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/jdi/MethodBytecodeUtil.java b/java/debugger/impl/src/com/intellij/debugger/jdi/MethodBytecodeUtil.java index 2ddcdfa137f9..4acff6976184 100644 --- a/java/debugger/impl/src/com/intellij/debugger/jdi/MethodBytecodeUtil.java +++ b/java/debugger/impl/src/com/intellij/debugger/jdi/MethodBytecodeUtil.java @@ -23,6 +23,7 @@ import org.jetbrains.org.objectweb.asm.*; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.IOException; +import java.util.Arrays; /** * @author egor @@ -35,26 +36,29 @@ public class MethodBytecodeUtil { * Allows to use ASM MethodVisitor with jdi method bytecode */ public static void visit(ClassType classType, Method method, MethodVisitor methodVisitor) { + visit(classType, method, method.bytecodes(), methodVisitor); + } + + public static void visit(ClassType classType, Method method, long maxOffset, MethodVisitor methodVisitor) { + visit(classType, method, Arrays.copyOf(method.bytecodes(), (int)maxOffset), methodVisitor); + } + + private static void visit(ClassType classType, Method method, byte[] bytecodes, MethodVisitor methodVisitor) { try { try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(bos)) { dos.writeInt(0xCAFEBABE); // magic dos.writeInt(Opcodes.V1_8); // version dos.writeShort(classType.constantPoolCount()); // constant_pool_count dos.write(classType.constantPool()); // constant_pool + dos.writeShort(0); // access_flags; + dos.writeShort(0); // this_class; + dos.writeShort(0); // super_class; + dos.writeShort(0); // interfaces_count; + dos.writeShort(0); // fields_count; + dos.writeShort(0); // methods_count; + dos.writeShort(0); // attributes_count; - // we generate and put code attribute right after the constant pool - byte[] bytecodes = method.bytecodes(); - int codeSize = dos.size(); - dos.writeShort(0); // max_stack - dos.writeShort(0); // max_locals - dos.writeInt(bytecodes.length); // code_length - dos.write(bytecodes); // code - dos.writeShort(0); // exception_table_length - dos.writeShort(0); // attributes_count - codeSize = dos.size() - codeSize; - - ClassReader clsReader = new ClassReader(bos.toByteArray()); - ClassWriter clsWriter = new ClassWriter(clsReader, 0); + ClassWriter clsWriter = new ClassWriter(new ClassReader(bos.toByteArray()), 0); clsWriter.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, classType.name(), @@ -62,11 +66,12 @@ public class MethodBytecodeUtil { classType.superclass().name(), classType.interfaces().stream().map(ReferenceType::name).toArray(String[]::new)); MethodVisitor mv = clsWriter.visitMethod(Opcodes.ACC_PUBLIC, method.name(), method.signature(), method.signature(), null); - mv.visitAttribute(createCode(clsReader, codeSize)); + mv.visitAttribute(createCode(bytecodes)); new ClassReader(clsWriter.toByteArray()).accept(new ClassVisitor(Opcodes.ASM5) { @Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { + assert name.equals(method.name()); return methodVisitor; } }, 0); @@ -76,13 +81,30 @@ public class MethodBytecodeUtil { } } - private static Attribute createCode(ClassReader cr, int len) { - return new Attribute("Code") { - @Override - public Attribute read(ClassReader cr, int off, int len, char[] buf, int codeOff, Label[] labels) { - return super.read(cr, off, len, buf, codeOff, labels); - } - }.read(cr, cr.header, len, null, 0, null); - } + private static Attribute createCode(byte[] bytecodes) throws IOException { + try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(bos)) { + dos.writeInt(0xCAFEBABE); // magic + dos.writeInt(Opcodes.V1_8); // version + dos.writeShort(0); // constant_pool_count + // we generate and put code attribute right after the constant pool + int codeSize = dos.size(); + dos.writeShort(0); // max_stack + dos.writeShort(0); // max_locals + dos.writeInt(bytecodes.length); // code_length + dos.write(bytecodes); // code + dos.writeShort(0); // exception_table_length + dos.writeShort(0); // attributes_count + codeSize = dos.size() - codeSize; + + ClassReader cr = new ClassReader(bos.toByteArray()); + + return new Attribute("Code") { + @Override + public Attribute read(ClassReader cr, int off, int len, char[] buf, int codeOff, Label[] labels) { + return super.read(cr, off, len, buf, codeOff, labels); + } + }.read(cr, cr.header, codeSize, null, 0, null); + } + } } From 1e4f85a26e70adfdeb86ba4a470df85f6f6f4ea4 Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Thu, 30 Jun 2016 16:11:06 +0300 Subject: [PATCH 08/50] Remove stale TODO comment --- .../inspections/quickfix/PyMakeFunctionFromMethodQuickFix.java | 1 - 1 file changed, 1 deletion(-) diff --git a/python/src/com/jetbrains/python/inspections/quickfix/PyMakeFunctionFromMethodQuickFix.java b/python/src/com/jetbrains/python/inspections/quickfix/PyMakeFunctionFromMethodQuickFix.java index 952f897683c6..c3cbe6535e4a 100644 --- a/python/src/com/jetbrains/python/inspections/quickfix/PyMakeFunctionFromMethodQuickFix.java +++ b/python/src/com/jetbrains/python/inspections/quickfix/PyMakeFunctionFromMethodQuickFix.java @@ -89,7 +89,6 @@ public class PyMakeFunctionFromMethodQuickFix implements LocalQuickFix { @NotNull final PsiFile usageFile, boolean addImport) { final PyExpression qualifier = element.getQualifier(); if (qualifier == null) return; - //TODO: invalid qualifier after PyUtil.removeQualifier(element), to be fixed by east825 if (qualifier.getText().equals(PyNames.CANONICAL_SELF)) { PyUtil.removeQualifier(element); return; From 1b941a951f84650bc67fc0053422ca11cb7bc5cb Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Fri, 1 Jul 2016 19:38:11 +0300 Subject: [PATCH 09/50] Don't request packages multiple times to get installed test frameworks It's not only redundant but also causes three identical errors with stacktraces in the log if we didn't manage to successfully run packaging_tool.py for some reason. Now we check status of all test frameworks in one pass. --- .../testing/VFSTestFrameworkListener.java | 29 +++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/python/src/com/jetbrains/python/testing/VFSTestFrameworkListener.java b/python/src/com/jetbrains/python/testing/VFSTestFrameworkListener.java index 98fa61101ef8..3f655edde3da 100644 --- a/python/src/com/jetbrains/python/testing/VFSTestFrameworkListener.java +++ b/python/src/com/jetbrains/python/testing/VFSTestFrameworkListener.java @@ -42,7 +42,9 @@ import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; /** @@ -102,9 +104,16 @@ public class VFSTestFrameworkListener { } public void updateAllTestFrameworks(@NotNull Sdk sdk) { - checkFrameworkInstalledAndUpdateSettings(sdk, PyNames.PY_TEST); - checkFrameworkInstalledAndUpdateSettings(sdk, PyNames.NOSE_TEST); - checkFrameworkInstalledAndUpdateSettings(sdk, PyNames.AT_TEST); + final Map whichInstalled = checkTestFrameworksInstalled(sdk, PyNames.PY_TEST, PyNames.NOSE_TEST, PyNames.AT_TEST); + ApplicationManager.getApplication().invokeLater(() -> { + for (Map.Entry entry : whichInstalled.entrySet()) { + final Boolean installed = entry.getValue(); + if (installed != null) { + //noinspection ConstantConditions + setTestFrameworkInstalled(installed, sdk.getHomePath(), entry.getKey()); + } + } + }); } private void scheduleTestFrameworkCheck(@NotNull Sdk sdk, @NotNull String testPackageName) { @@ -129,19 +138,27 @@ public class VFSTestFrameworkListener { */ @Contract("null, _ -> null") private Boolean checkTestFrameworkInstalled(@Nullable Sdk sdk, @NotNull String testPackageName) { + return checkTestFrameworksInstalled(sdk, testPackageName).get(testPackageName); + } + + @NotNull + private Map checkTestFrameworksInstalled(@Nullable Sdk sdk, @NotNull String... testPackageNames) { + final Map result = new HashMap<>(); if (sdk == null || StringUtil.isEmptyOrSpaces(sdk.getHomePath())) { LOG.info("Searching test runner in empty sdk"); - return null; + return result; } final PyPackageManager manager = PyPackageManager.getInstance(sdk); final boolean refreshed = PyPackageUtil.updatePackagesSynchronouslyWithGuard(manager, myIsUpdating); if (refreshed) { final List packages = manager.getPackages(); if (packages != null) { - return PyPackageUtil.findPackage(packages, testPackageName) != null; + for (String name : testPackageNames) { + result.put(name, PyPackageUtil.findPackage(packages, name) != null); + } } } - return null; + return result; } private void setPyTestInstalled(boolean installed, @NotNull String sdkHome) { From 209ef1d51d2fbbd2ad866d6c00e620c871ac3bbd Mon Sep 17 00:00:00 2001 From: Valentin Fondaratov Date: Fri, 1 Jul 2016 13:36:33 +0300 Subject: [PATCH 10/50] Deprecate unused API; cleanup usages --- .../intellij/codeInsight/dataflow/DFAEngine.java | 15 ++++----------- .../codeInsight/dataflow/DfaInstance.java | 3 +++ 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/dataflow/DFAEngine.java b/platform/lang-impl/src/com/intellij/codeInsight/dataflow/DFAEngine.java index 79c7266f5d17..f89260919b09 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/dataflow/DFAEngine.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/dataflow/DFAEngine.java @@ -57,15 +57,14 @@ public class DFAEngine { final boolean[] visited = new boolean[myFlow.length]; - final boolean forward = myDfa.isForward(); final int[] order = ControlFlowUtil.postOrder(myFlow); // Count limit for number of iterations per worklist - final int limit = getIterationLimit(forward); + final int limit = getIterationLimit(); int dfaCount = 0; final long startTime = System.nanoTime(); - for (int i = forward ? 0 : myFlow.length - 1; forward ? i < myFlow.length : i >= 0; ) { + for (int i = 0; i < myFlow.length; i++) { // Check if canceled ProgressManager.checkCanceled(); @@ -124,12 +123,6 @@ public class DFAEngine { } // Move to another worklist - if (forward) { - i++; - } - else { - i--; - } dfaCount += count; } if (LOG.isDebugEnabled()) { @@ -144,10 +137,10 @@ public class DFAEngine { * Every node in dfa should be processed <= pred times * 2 * Multiplier 2 is because of cycles. */ - private int getIterationLimit(final boolean forward) { + private int getIterationLimit() { int allPred = myFlow.length; for (Instruction instruction : myFlow) { - allPred += forward ? instruction.allPred().size() : instruction.allSucc().size(); + allPred += instruction.allPred().size(); } return allPred * 2; } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/dataflow/DfaInstance.java b/platform/lang-impl/src/com/intellij/codeInsight/dataflow/DfaInstance.java index 894e54d0af5b..eea25a3e34c8 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/dataflow/DfaInstance.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/dataflow/DfaInstance.java @@ -26,5 +26,8 @@ public interface DfaInstance { @NotNull E initial(); + /** + * @deprecated + */ boolean isForward(); } From f71969671568c07486d27fc7e04577e09f59730e Mon Sep 17 00:00:00 2001 From: Valentin Fondaratov Date: Mon, 4 Jul 2016 12:37:34 +0300 Subject: [PATCH 11/50] change YAMLKeyValue icon retrieval This will help delegate to KV's icon easier as well as preserve an ability to overload it in IconProvider --- .../src/org/jetbrains/yaml/psi/impl/YAMLKeyValueImpl.java | 8 +++++++- .../yaml/structureView/YAMLStructureViewElement.java | 5 ++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLKeyValueImpl.java b/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLKeyValueImpl.java index 6c1e0737cc5b..020b0ae9c980 100644 --- a/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLKeyValueImpl.java +++ b/plugins/yaml/src/org/jetbrains/yaml/psi/impl/YAMLKeyValueImpl.java @@ -138,6 +138,12 @@ public class YAMLKeyValueImpl extends YAMLPsiElementImpl implements YAMLKeyValue } } + @NotNull + @Override + protected Icon getElementIcon(@IconFlags int flags) { + return PlatformIcons.PROPERTY_ICON; + } + @Override public ItemPresentation getPresentation() { final YAMLFile yamlFile = (YAMLFile)getContainingFile(); @@ -155,7 +161,7 @@ public class YAMLKeyValueImpl extends YAMLPsiElementImpl implements YAMLKeyValue } public Icon getIcon(boolean open) { - return PlatformIcons.PROPERTY_ICON; + return YAMLKeyValueImpl.this.getIcon(0); } }; } diff --git a/plugins/yaml/src/org/jetbrains/yaml/structureView/YAMLStructureViewElement.java b/plugins/yaml/src/org/jetbrains/yaml/structureView/YAMLStructureViewElement.java index ee690a525bbf..46678f2d2706 100644 --- a/plugins/yaml/src/org/jetbrains/yaml/structureView/YAMLStructureViewElement.java +++ b/plugins/yaml/src/org/jetbrains/yaml/structureView/YAMLStructureViewElement.java @@ -2,7 +2,6 @@ package org.jetbrains.yaml.structureView; import com.intellij.ide.structureView.StructureViewTreeElement; import com.intellij.navigation.ItemPresentation; -import com.intellij.psi.PsiElement; import com.intellij.util.PlatformIcons; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -82,8 +81,8 @@ public class YAMLStructureViewElement implements StructureViewTreeElement { } public Icon getIcon(boolean open) { - final PsiElement value = kv.getValue(); - return value instanceof YAMLScalar ? PlatformIcons.PROPERTY_ICON : PlatformIcons.XML_TAG_ICON; + final YAMLValue value = kv.getValue(); + return value instanceof YAMLScalar ? kv.getIcon(0) : PlatformIcons.XML_TAG_ICON; } }; } From fccf1cf7f99524cddc62e084b345b95fe0443b75 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 4 Jul 2016 12:56:35 +0300 Subject: [PATCH 12/50] cancel nav. popups: accept cancel from the first attempt --- .../codeInsight/daemon/impl/PsiElementListNavigator.java | 2 +- .../com/intellij/codeInsight/navigation/GotoTargetHandler.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PsiElementListNavigator.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PsiElementListNavigator.java index 5396c133dfc1..259aecaa5e0f 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PsiElementListNavigator.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PsiElementListNavigator.java @@ -145,7 +145,7 @@ public class PsiElementListNavigator { setCancelCallback(() -> { HintUpdateSupply.hideHint(list); if (listUpdaterTask != null) { - return listUpdaterTask.cancelTask(); + listUpdaterTask.cancelTask(); } return true; }); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/navigation/GotoTargetHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/navigation/GotoTargetHandler.java index a5b1ecf27c97..6ca91442f373 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/navigation/GotoTargetHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/navigation/GotoTargetHandler.java @@ -184,7 +184,7 @@ public abstract class GotoTargetHandler implements CodeInsightActionHandler { HintUpdateSupply.hideHint(list); final ListBackgroundUpdaterTask task = gotoData.listUpdaterTask; if (task != null) { - return task.cancelTask(); + task.cancelTask(); } return true; }). From 3b6c64fadd9066696e1846e2a122a4da416fc39d Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Mon, 4 Jul 2016 13:38:17 +0300 Subject: [PATCH 13/50] [git] system date format in annotation tooltips --- .../git4idea/src/git4idea/annotate/GitFileAnnotation.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/git4idea/src/git4idea/annotate/GitFileAnnotation.java b/plugins/git4idea/src/git4idea/annotate/GitFileAnnotation.java index 156f171fb643..faa4425785b0 100644 --- a/plugins/git4idea/src/git4idea/annotate/GitFileAnnotation.java +++ b/plugins/git4idea/src/git4idea/annotate/GitFileAnnotation.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -101,8 +101,8 @@ public class GitFileAnnotation extends FileAnnotation { final LineInfo info = myLines.get(lineNumber); VcsFileRevision fileRevision = info.myFileRevision; if (fileRevision != null) { - return GitBundle.message("annotation.tool.tip", info.getRevision().asString(), info.getAuthor(), info.getDate(), - fileRevision.getCommitMessage()); + return GitBundle.message("annotation.tool.tip", info.getRevision().asString(), info.getAuthor(), + DateFormatUtil.formatDateTime(info.getDate()), fileRevision.getCommitMessage()); } else { return ""; From 8dd269e7dbe1ef7d035480f94ba75417fe11c63c Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Mon, 4 Jul 2016 13:39:00 +0300 Subject: [PATCH 14/50] Cleanup (deprecated API) --- .../util/src/com/intellij/util/text/DateFormatUtil.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/platform/util/src/com/intellij/util/text/DateFormatUtil.java b/platform/util/src/com/intellij/util/text/DateFormatUtil.java index 0abbf6bc4679..096de12833a2 100644 --- a/platform/util/src/com/intellij/util/text/DateFormatUtil.java +++ b/platform/util/src/com/intellij/util/text/DateFormatUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -75,10 +75,6 @@ public class DateFormatUtil { private DateFormatUtil() { } - /** @deprecated use {@link #getIso8601Format()} (to be removed in IDEA 16) */ - @SuppressWarnings("unused") - public static final SyncDateFormat ISO8601_DATE_FORMAT = ISO8601_FORMAT; - public static long getDifferenceInDays(@NotNull Date startDate, @NotNull Date endDate) { return (endDate.getTime() - startDate.getTime() + DAY_FACTOR - 1000) / DAY_FACTOR; } From 448e0578fde512ad799ae6ce6a74a1185955d1dc Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Mon, 4 Jul 2016 13:46:17 +0300 Subject: [PATCH 15/50] Cleanup (wording) --- .../platform-resources-en/src/messages/LangBundle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/platform-resources-en/src/messages/LangBundle.properties b/platform/platform-resources-en/src/messages/LangBundle.properties index 9d140ebe16d8..37b5dea09dc5 100644 --- a/platform/platform-resources-en/src/messages/LangBundle.properties +++ b/platform/platform-resources-en/src/messages/LangBundle.properties @@ -54,7 +54,7 @@ incorrect.name=Incorrect name jrt.node.short=[JRT] jrt.node.long=[Java Run-time Modules] -jrt.not.available.message=You need to run IDEA on Java 8 to be able to use modular JDK. Sorry. +jrt.not.available.message=You need to run IDEA on Java 8+ to be able to use modular JDK. Sorry. jrt.not.available.title=Unsupported JDK ''{0}'' detected compound.run.configuration.cycle={0} ''{1}'' causes dependency cycle and cannot be added From adba44ddf40cf3ce84ea7af0ee36b8ff49755ed0 Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Mon, 4 Jul 2016 12:55:53 +0200 Subject: [PATCH 16/50] advance index version --- .../psi/impl/java/stubs/index/JavaShortClassNameIndex.java | 2 +- .../src/com/intellij/psi/search/FilenameIndex.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/java/stubs/index/JavaShortClassNameIndex.java b/java/java-indexing-impl/src/com/intellij/psi/impl/java/stubs/index/JavaShortClassNameIndex.java index 5f0d9298b1cc..d3a76c2fb37e 100644 --- a/java/java-indexing-impl/src/com/intellij/psi/impl/java/stubs/index/JavaShortClassNameIndex.java +++ b/java/java-indexing-impl/src/com/intellij/psi/impl/java/stubs/index/JavaShortClassNameIndex.java @@ -41,7 +41,7 @@ public class JavaShortClassNameIndex extends StringStubIndexExtension @Override public int getVersion() { - return super.getVersion() + (FileBasedIndex.ourEnableTracingOfKeyHashToVirtualFileMapping ? 1 : 0); + return super.getVersion() + (FileBasedIndex.ourEnableTracingOfKeyHashToVirtualFileMapping ? 2 : 0); } @NotNull diff --git a/platform/indexing-impl/src/com/intellij/psi/search/FilenameIndex.java b/platform/indexing-impl/src/com/intellij/psi/search/FilenameIndex.java index 0bee35cdbf9a..e1416c5cb667 100644 --- a/platform/indexing-impl/src/com/intellij/psi/search/FilenameIndex.java +++ b/platform/indexing-impl/src/com/intellij/psi/search/FilenameIndex.java @@ -80,7 +80,7 @@ public class FilenameIndex extends ScalarIndexExtension { @Override public int getVersion() { - return 1 + (FileBasedIndex.ourEnableTracingOfKeyHashToVirtualFileMapping ? 1 : 0); + return 1 + (FileBasedIndex.ourEnableTracingOfKeyHashToVirtualFileMapping ? 2 : 0); } public static String[] getAllFilenames(Project project) { From c78e91e07d4e306b91868a9bdee6d7e8e1e5349a Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Thu, 30 Jun 2016 19:04:30 +0300 Subject: [PATCH 17/50] lst: refresh only after the last of enclosed WriteActions We don't use afterWriteActionFinished because we want to update inside same WriteLock section. --- .../intellij/openapi/vcs/ex/LineStatusTracker.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java index 94045c141fa9..dc6947ae5461 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java @@ -398,9 +398,19 @@ public class LineStatusTracker { } private class MyApplicationListener extends ApplicationAdapter { + private int myWriteActionDepth = 0; + + @Override + public void writeActionStarted(@NotNull Object action) { + myWriteActionDepth++; + } + @Override public void writeActionFinished(@NotNull Object action) { - updateRanges(); + myWriteActionDepth = Math.max(myWriteActionDepth - 1, 0); + if (myWriteActionDepth == 0) { + updateRanges(); + } } } From 65a5b0e4378359eae11b1925ed48fcb630c52078 Mon Sep 17 00:00:00 2001 From: Pavel Dolgov Date: Mon, 4 Jul 2016 14:36:59 +0300 Subject: [PATCH 18/50] Java intention: Quick fix for error "foreach not applicable to type java.util.Iterator" - handle comments and take care of empty block when copying the loop body (IDEA-124751) --- ...atorForEachLoopWithIteratorForLoopFix.java | 12 ++++++----- .../afterCodeBlockBody.java | 1 + .../afterEmptyBlockBody.java | 10 ++++++++++ .../beforeCodeBlockBody.java | 1 + .../beforeEmptyBlockBody.java | 8 ++++++++ ...ForEachLoopWithIteratorForLoopFixTest.java | 20 +++++++++++-------- 6 files changed, 39 insertions(+), 13 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceIteratorForEachWithFor/afterEmptyBlockBody.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceIteratorForEachWithFor/beforeEmptyBlockBody.java diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ReplaceIteratorForEachLoopWithIteratorForLoopFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ReplaceIteratorForEachLoopWithIteratorForLoopFix.java index 2d71379b96a0..df5ffe1b6976 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ReplaceIteratorForEachLoopWithIteratorForLoopFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ReplaceIteratorForEachLoopWithIteratorForLoopFix.java @@ -42,14 +42,14 @@ public class ReplaceIteratorForEachLoopWithIteratorForLoopFix implements Intenti @NotNull @Override public String getText() { - return "Replace 'for each' loop with iterator 'for' loop"; + return getFamilyName(); } @Nls @NotNull @Override public String getFamilyName() { - return getText(); + return "Replace 'for each' loop with iterator 'for' loop"; } @Override @@ -112,9 +112,11 @@ public class ReplaceIteratorForEachLoopWithIteratorForLoopFix implements Intenti newForLoop = (PsiForStatement)styleManager.reformat(newForLoop); if (forEachBody instanceof PsiBlockStatement) { - final PsiStatement[] statements = ((PsiBlockStatement)forEachBody).getCodeBlock().getStatements(); - for (int i = statements.length - 1; i >= 0; i--) { - newBodyBlock.addAfter(statements[i], newFirstStatement); + final PsiCodeBlock bodyCodeBlock = ((PsiBlockStatement)forEachBody).getCodeBlock(); + final PsiElement firstBodyElement = bodyCodeBlock.getFirstBodyElement(); + final PsiElement lastBodyElement = bodyCodeBlock.getLastBodyElement(); + if (firstBodyElement != null && lastBodyElement != null) { + newBodyBlock.addRangeAfter(firstBodyElement, lastBodyElement, newFirstStatement); } } else if (forEachBody != null && !(forEachBody instanceof PsiEmptyStatement)) { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceIteratorForEachWithFor/afterCodeBlockBody.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceIteratorForEachWithFor/afterCodeBlockBody.java index bc57adb5ee1d..85ba91197a34 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceIteratorForEachWithFor/afterCodeBlockBody.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceIteratorForEachWithFor/afterCodeBlockBody.java @@ -6,6 +6,7 @@ public class CodeBlockBody { for (Iterator it2 = it1; it2.hasNext(); ) { Integer integer = it2.next(); System.out.println(integer + " a"); + // a comment System.out.println(integer + " b"); } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceIteratorForEachWithFor/afterEmptyBlockBody.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceIteratorForEachWithFor/afterEmptyBlockBody.java new file mode 100644 index 000000000000..eaa1ba970096 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceIteratorForEachWithFor/afterEmptyBlockBody.java @@ -0,0 +1,10 @@ +// "Replace 'for each' loop with iterator 'for' loop" "true" +import java.util.Iterator; + +public class EmptyBlockBody { + void foo(Iterator it) { + for (Iterator it1 = it; it1.hasNext(); ) { + Integer integer = it1.next(); + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceIteratorForEachWithFor/beforeCodeBlockBody.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceIteratorForEachWithFor/beforeCodeBlockBody.java index 4e98a66b426d..3aeabbfe935f 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceIteratorForEachWithFor/beforeCodeBlockBody.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceIteratorForEachWithFor/beforeCodeBlockBody.java @@ -5,6 +5,7 @@ public class CodeBlockBody { void foo(Iterator it,Iterator it1) { for (Integer integer : it1) { System.out.println(integer + " a"); + // a comment System.out.println(integer + " b"); } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceIteratorForEachWithFor/beforeEmptyBlockBody.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceIteratorForEachWithFor/beforeEmptyBlockBody.java new file mode 100644 index 000000000000..2ca6d3cf5ef4 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceIteratorForEachWithFor/beforeEmptyBlockBody.java @@ -0,0 +1,8 @@ +// "Replace 'for each' loop with iterator 'for' loop" "true" +import java.util.Iterator; + +public class EmptyBlockBody { + void foo(Iterator it) { + for (Integer integer : it) {} + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/ReplaceIteratorForEachLoopWithIteratorForLoopFixTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/ReplaceIteratorForEachLoopWithIteratorForLoopFixTest.java index cd7f9319a322..bb4ead8a28f1 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/ReplaceIteratorForEachLoopWithIteratorForLoopFixTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/ReplaceIteratorForEachLoopWithIteratorForLoopFixTest.java @@ -28,9 +28,9 @@ public class ReplaceIteratorForEachLoopWithIteratorForLoopFixTest extends LightQ public void test() throws Exception { doAllTests(); } @Override - protected void beforeActionStarted(String testName, String contents) { - super.beforeActionStarted(testName, contents); - if (testName.startsWith("Final")) { + protected void setUp() throws Exception { + super.setUp(); + if (getTestName(false).startsWith("Final")) { final CodeStyleSettings codeStyleSettings = CodeStyleSettingsManager.getSettings(getProject()); myFinalLocals = codeStyleSettings.GENERATE_FINAL_LOCALS; codeStyleSettings.GENERATE_FINAL_LOCALS = true; @@ -38,12 +38,16 @@ public class ReplaceIteratorForEachLoopWithIteratorForLoopFixTest extends LightQ } @Override - protected void afterActionCompleted(String testName, String contents) { - if (testName.startsWith("Final")) { - final CodeStyleSettings codeStyleSettings = CodeStyleSettingsManager.getSettings(getProject()); - codeStyleSettings.GENERATE_FINAL_LOCALS = myFinalLocals; + protected void tearDown() throws Exception { + try { + if (getTestName(false).startsWith("Final")) { + final CodeStyleSettings codeStyleSettings = CodeStyleSettingsManager.getSettings(getProject()); + codeStyleSettings.GENERATE_FINAL_LOCALS = myFinalLocals; + } + } + finally { + super.tearDown(); } - super.afterActionCompleted(testName, contents); } @Override From 15bb7ce510a86ac95a63e67ec407e4c0c8cb7866 Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Mon, 4 Jul 2016 13:55:10 +0200 Subject: [PATCH 19/50] Clear channel attributes on channel unregister to avoid project leaks (IDEA-158108) --- .../intellij/compiler/server/BuildMessageDispatcher.java | 9 ++++++++- .../org/jetbrains/jps/javac/ExternalJavacManager.java | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/java/compiler/impl/src/com/intellij/compiler/server/BuildMessageDispatcher.java b/java/compiler/impl/src/com/intellij/compiler/server/BuildMessageDispatcher.java index 2624cde1af17..ed3bbba1709c 100644 --- a/java/compiler/impl/src/com/intellij/compiler/server/BuildMessageDispatcher.java +++ b/java/compiler/impl/src/com/intellij/compiler/server/BuildMessageDispatcher.java @@ -71,7 +71,14 @@ class BuildMessageDispatcher extends SimpleChannelInboundHandlerAdapter { @Override public void channelUnregistered(ChannelHandlerContext ctx) throws Exception { - JavacProcessDescriptor descriptor = ctx.channel().attr(SESSION_DESCRIPTOR).get(); + JavacProcessDescriptor descriptor = ctx.channel().attr(SESSION_DESCRIPTOR).getAndRemove(); if (descriptor != null) { descriptor.setDone(); } From f6a13bd94cf9084a046597aec90ab0e1cf07222c Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Mon, 4 Jul 2016 12:54:05 +0200 Subject: [PATCH 20/50] IG: cleanup --- ...ssignmentToForLoopParameterInspection.java | 8 ++--- ...ultiplyOrDivideByPowerOfTwoInspection.java | 6 +--- .../ig/psiutils/WellFormednessUtils.java | 32 ------------------- 3 files changed, 4 insertions(+), 42 deletions(-) delete mode 100644 plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/WellFormednessUtils.java diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/assignment/AssignmentToForLoopParameterInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/assignment/AssignmentToForLoopParameterInspection.java index fa4ffac5679e..e7b45b30a671 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/assignment/AssignmentToForLoopParameterInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/assignment/AssignmentToForLoopParameterInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2011 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2016 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,7 +24,6 @@ import com.siyeh.ig.BaseInspection; import com.siyeh.ig.BaseInspectionVisitor; import com.siyeh.ig.InspectionGadgetsFix; import com.siyeh.ig.fixes.ExtractParameterAsLocalVariableFix; -import com.siyeh.ig.psiutils.WellFormednessUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -79,10 +78,9 @@ public class AssignmentToForLoopParameterInspection extends BaseInspectionVisitor { @Override - public void visitAssignmentExpression( - @NotNull PsiAssignmentExpression expression) { + public void visitAssignmentExpression(@NotNull PsiAssignmentExpression expression) { super.visitAssignmentExpression(expression); - if (!WellFormednessUtils.isWellFormed(expression)) { + if (expression.getRExpression() == null) { return; } final PsiExpression lhs = expression.getLExpression(); diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/j2me/MultiplyOrDivideByPowerOfTwoInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/j2me/MultiplyOrDivideByPowerOfTwoInspection.java index 217ece7078ba..d913e1c36837 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/j2me/MultiplyOrDivideByPowerOfTwoInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/j2me/MultiplyOrDivideByPowerOfTwoInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2008 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2016 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,7 +28,6 @@ import com.siyeh.ig.InspectionGadgetsFix; import com.siyeh.ig.PsiReplacementUtil; import com.siyeh.ig.psiutils.ClassUtils; import com.siyeh.ig.psiutils.ParenthesesUtils; -import com.siyeh.ig.psiutils.WellFormednessUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -194,9 +193,6 @@ public class MultiplyOrDivideByPowerOfTwoInspection @Override public void visitAssignmentExpression(@NotNull PsiAssignmentExpression expression) { super.visitAssignmentExpression(expression); - if (!WellFormednessUtils.isWellFormed(expression)) { - return; - } final IElementType tokenType = expression.getOperationTokenType(); if (!tokenType.equals(JavaTokenType.ASTERISKEQ)) { if (!checkDivision || !tokenType.equals(JavaTokenType.DIVEQ)) { diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/WellFormednessUtils.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/WellFormednessUtils.java deleted file mode 100644 index 6c8bce382525..000000000000 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/WellFormednessUtils.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2003-2005 Dave Griffith - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.siyeh.ig.psiutils; - -import com.intellij.psi.PsiAssignmentExpression; -import com.intellij.psi.PsiExpression; -import org.jetbrains.annotations.NotNull; - -public class WellFormednessUtils { - private WellFormednessUtils() { - super(); - } - - public static boolean isWellFormed(@NotNull PsiAssignmentExpression expression) { - - final PsiExpression rhs = expression.getRExpression(); - return rhs != null; - } -} From 5fe0ca75e9e30c28cf99c5581bd5a829b95c1220 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Mon, 4 Jul 2016 13:38:05 +0200 Subject: [PATCH 21/50] IG: rename util --- .../impl/quickfix/SimplifyBooleanExpressionFix.java | 5 ++--- .../ig/bugs/OptionalGetWithoutIsPresentInspection.java | 4 ++-- .../ig/controlflow/ConstantIfStatementInspection.java | 6 +++--- .../errorhandling/UnnecessaryInitCauseInspectionBase.java | 6 +++--- .../src/com/siyeh/ig/fixes/DeleteCatchSectionFix.java | 7 +++---- .../MisorderedAssertEqualsArgumentsInspectionBase.java | 4 ++-- ...riableSearchUtils.java => DeclarationSearchUtils.java} | 4 ++-- .../ig/style/UnnecessaryBlockStatementInspection.java | 4 ++-- .../src/com/siyeh/ig/style/UnnecessaryThisInspection.java | 8 ++++---- ...izationOnLocalVariableOrMethodParameterInspection.java | 6 +++--- .../ipp/exceptions/ConvertCatchToThrowsIntention.java | 4 ++-- 11 files changed, 28 insertions(+), 30 deletions(-) rename plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/{VariableSearchUtils.java => DeclarationSearchUtils.java} (98%) diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/SimplifyBooleanExpressionFix.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/SimplifyBooleanExpressionFix.java index e94b653a87c5..26074ccd50ad 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/SimplifyBooleanExpressionFix.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/SimplifyBooleanExpressionFix.java @@ -29,10 +29,9 @@ import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; -import com.intellij.util.Function; import com.intellij.util.IncorrectOperationException; import com.siyeh.ig.psiutils.ParenthesesUtils; -import com.siyeh.ig.psiutils.VariableSearchUtils; +import com.siyeh.ig.psiutils.DeclarationSearchUtils; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -131,7 +130,7 @@ public class SimplifyBooleanExpressionFix extends LocalQuickFixOnPsiElement { PsiElement parent = orig.getParent(); if (parent == null) return; if (statement instanceof PsiBlockStatement && parent instanceof PsiCodeBlock && - !VariableSearchUtils.containsConflictingDeclarations(((PsiBlockStatement)statement).getCodeBlock(), (PsiCodeBlock)parent)) { + !DeclarationSearchUtils.containsConflictingDeclarations(((PsiBlockStatement)statement).getCodeBlock(), (PsiCodeBlock)parent)) { // See IDEADEV-24277 // Code block can only be inlined into another (parent) code block. // Code blocks, which are if or loop statement branches should not be inlined. diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/OptionalGetWithoutIsPresentInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/OptionalGetWithoutIsPresentInspection.java index cff4e0bca6f0..dc9c9b15194b 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/OptionalGetWithoutIsPresentInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/OptionalGetWithoutIsPresentInspection.java @@ -257,8 +257,8 @@ public class OptionalGetWithoutIsPresentInspection extends BaseInspection { } else if (expression instanceof PsiReferenceExpression) { final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)expression; - final PsiExpression definition = VariableSearchUtils.findDefinition(referenceExpression, null); - final PsiExpression optionalDefinition = VariableSearchUtils.findDefinition(this.referenceExpression, null); + final PsiExpression definition = DeclarationSearchUtils.findDefinition(referenceExpression, null); + final PsiExpression optionalDefinition = DeclarationSearchUtils.findDefinition(this.referenceExpression, null); if (definition == null || optionalDefinition == null || optionalDefinition.getTextOffset() > definition.getTextOffset()) { return false; } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/controlflow/ConstantIfStatementInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/controlflow/ConstantIfStatementInspection.java index 645fc426027d..de7cd1053bfb 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/controlflow/ConstantIfStatementInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/controlflow/ConstantIfStatementInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2010 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2016 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,7 +27,7 @@ import com.siyeh.ig.BaseInspectionVisitor; import com.siyeh.ig.InspectionGadgetsFix; import com.siyeh.ig.PsiReplacementUtil; import com.siyeh.ig.psiutils.BoolUtils; -import com.siyeh.ig.psiutils.VariableSearchUtils; +import com.siyeh.ig.psiutils.DeclarationSearchUtils; import org.jetbrains.annotations.NotNull; public class ConstantIfStatementInspection extends BaseInspection { @@ -116,7 +116,7 @@ public class ConstantIfStatementInspection extends BaseInspection { final PsiCodeBlock block = ((PsiBlockStatement)branch).getCodeBlock(); final boolean hasConflicts = - VariableSearchUtils.containsConflictingDeclarations( + DeclarationSearchUtils.containsConflictingDeclarations( block, parentBlock); if (hasConflicts) { final String elseText = branch.getText(); diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/errorhandling/UnnecessaryInitCauseInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/errorhandling/UnnecessaryInitCauseInspectionBase.java index 2a915015e6f1..31611d90a4da 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/errorhandling/UnnecessaryInitCauseInspectionBase.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/errorhandling/UnnecessaryInitCauseInspectionBase.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,7 +26,7 @@ import com.siyeh.ig.BaseInspectionVisitor; import com.siyeh.ig.psiutils.ExpressionUtils; import com.siyeh.ig.psiutils.ParenthesesUtils; import com.siyeh.ig.psiutils.TypeUtils; -import com.siyeh.ig.psiutils.VariableSearchUtils; +import com.siyeh.ig.psiutils.DeclarationSearchUtils; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -162,7 +162,7 @@ public class UnnecessaryInitCauseInspectionBase extends BaseInspection { } else if (expression instanceof PsiReferenceExpression) { final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)expression; - final PsiExpression definition = VariableSearchUtils.findDefinition(referenceExpression, null); + final PsiExpression definition = DeclarationSearchUtils.findDefinition(referenceExpression, null); if (!(definition instanceof PsiNewExpression)) { return null; } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/fixes/DeleteCatchSectionFix.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/fixes/DeleteCatchSectionFix.java index e110d0d96f2b..c1c0c335a871 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/fixes/DeleteCatchSectionFix.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/fixes/DeleteCatchSectionFix.java @@ -18,10 +18,9 @@ package com.siyeh.ig.fixes; import com.intellij.codeInspection.ProblemDescriptor; import com.intellij.openapi.project.Project; import com.intellij.psi.*; -import com.intellij.util.IncorrectOperationException; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.InspectionGadgetsFix; -import com.siyeh.ig.psiutils.VariableSearchUtils; +import com.siyeh.ig.psiutils.DeclarationSearchUtils; import org.jetbrains.annotations.NotNull; /** @@ -53,7 +52,7 @@ public class DeleteCatchSectionFix extends InspectionGadgetsFix { } @Override - protected void doFix(Project project, ProblemDescriptor descriptor) throws IncorrectOperationException { + protected void doFix(Project project, ProblemDescriptor descriptor) { final PsiElement element = descriptor.getPsiElement(); final PsiElement parent = element.getParent(); if (!(parent instanceof PsiParameter)) { @@ -75,7 +74,7 @@ public class DeleteCatchSectionFix extends InspectionGadgetsFix { final boolean keepBlock; if (containingElement instanceof PsiCodeBlock) { final PsiCodeBlock parentBlock = (PsiCodeBlock)containingElement; - keepBlock = VariableSearchUtils.containsConflictingDeclarations(codeBlock, parentBlock); + keepBlock = DeclarationSearchUtils.containsConflictingDeclarations(codeBlock, parentBlock); } else { keepBlock = true; diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/MisorderedAssertEqualsArgumentsInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/MisorderedAssertEqualsArgumentsInspectionBase.java index fa4e9dcabf91..d9f3779709ee 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/MisorderedAssertEqualsArgumentsInspectionBase.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/junit/MisorderedAssertEqualsArgumentsInspectionBase.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 JetBrains s.r.o. + * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -210,7 +210,7 @@ public abstract class MisorderedAssertEqualsArgumentsInspectionBase extends Base } else if (target instanceof PsiLocalVariable) { final PsiVariable variable = (PsiLocalVariable)target; - final PsiExpression definition = VariableSearchUtils.findDefinition(referenceExpression, variable); + final PsiExpression definition = DeclarationSearchUtils.findDefinition(referenceExpression, variable); if (LibraryUtil.isOnlyLibraryCodeUsed(definition)) { return true; } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/VariableSearchUtils.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/DeclarationSearchUtils.java similarity index 98% rename from plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/VariableSearchUtils.java rename to plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/DeclarationSearchUtils.java index 1c3bf112d86b..59547dffdae3 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/VariableSearchUtils.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/DeclarationSearchUtils.java @@ -25,9 +25,9 @@ import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; -public class VariableSearchUtils { +public class DeclarationSearchUtils { - private VariableSearchUtils() {} + private DeclarationSearchUtils() {} public static boolean variableNameResolvesToTarget( @NotNull String variableName, @NotNull PsiVariable target, diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/UnnecessaryBlockStatementInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/UnnecessaryBlockStatementInspection.java index 59e5c5f8c5ed..85e8be01c4de 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/UnnecessaryBlockStatementInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/UnnecessaryBlockStatementInspection.java @@ -25,7 +25,7 @@ import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; import com.siyeh.ig.BaseInspectionVisitor; import com.siyeh.ig.InspectionGadgetsFix; -import com.siyeh.ig.psiutils.VariableSearchUtils; +import com.siyeh.ig.psiutils.DeclarationSearchUtils; import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -127,7 +127,7 @@ public class UnnecessaryBlockStatementInspection extends BaseInspection implemen } final PsiCodeBlock parentBlock = (PsiCodeBlock)parent; if (parentBlock.getStatements().length > 1 && - VariableSearchUtils.containsConflictingDeclarations(codeBlock, parentBlock)) { + DeclarationSearchUtils.containsConflictingDeclarations(codeBlock, parentBlock)) { return; } registerError(brace); diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/UnnecessaryThisInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/UnnecessaryThisInspection.java index 6c4051066ad5..8ca514b0cc09 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/UnnecessaryThisInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/UnnecessaryThisInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2013 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2016 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,7 +30,7 @@ import com.siyeh.ig.BaseInspectionVisitor; import com.siyeh.ig.InspectionGadgetsFix; import com.siyeh.ig.PsiReplacementUtil; import com.siyeh.ig.psiutils.ClassUtils; -import com.siyeh.ig.psiutils.VariableSearchUtils; +import com.siyeh.ig.psiutils.DeclarationSearchUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -134,7 +134,7 @@ public class UnnecessaryThisInspection extends BaseInspection implements Cleanup return; } final PsiVariable variable = (PsiVariable)target; - if (!VariableSearchUtils.variableNameResolvesToTarget(referenceName, variable, expression)) { + if (!DeclarationSearchUtils.variableNameResolvesToTarget(referenceName, variable, expression)) { return; } if (variable instanceof PsiField && HighlightUtil.isIllegalForwardReferenceToField(expression, (PsiField)variable, true) != null) { @@ -181,7 +181,7 @@ public class UnnecessaryThisInspection extends BaseInspection implements Cleanup return; } final PsiVariable variable = (PsiVariable)target; - if (!VariableSearchUtils.variableNameResolvesToTarget(referenceName, variable, expression)) { + if (!DeclarationSearchUtils.variableNameResolvesToTarget(referenceName, variable, expression)) { return; } PsiClass parentClass = ClassUtils.getContainingClass(expression); diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/SynchronizationOnLocalVariableOrMethodParameterInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/SynchronizationOnLocalVariableOrMethodParameterInspection.java index c3334ebb0d5d..de0e58a7e218 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/SynchronizationOnLocalVariableOrMethodParameterInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/SynchronizationOnLocalVariableOrMethodParameterInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2008-2015 Bas Leijdekkers + * Copyright 2008-2016 Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,7 +21,7 @@ import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; import com.siyeh.ig.BaseInspectionVisitor; import com.siyeh.ig.psiutils.ParenthesesUtils; -import com.siyeh.ig.psiutils.VariableSearchUtils; +import com.siyeh.ig.psiutils.DeclarationSearchUtils; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; @@ -117,7 +117,7 @@ public class SynchronizationOnLocalVariableOrMethodParameterInspection extends B } private boolean isSynchronizedCollection(@NotNull PsiVariable variable, PsiReferenceExpression referenceExpression) { - final PsiExpression definition = VariableSearchUtils.findDefinition(referenceExpression, variable); + final PsiExpression definition = DeclarationSearchUtils.findDefinition(referenceExpression, variable); if (!(definition instanceof PsiMethodCallExpression)) { return false; } diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/ConvertCatchToThrowsIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/ConvertCatchToThrowsIntention.java index 0673d6f64b50..0bc45c67a74a 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/ConvertCatchToThrowsIntention.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/ConvertCatchToThrowsIntention.java @@ -20,7 +20,7 @@ import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.IncorrectOperationException; -import com.siyeh.ig.psiutils.VariableSearchUtils; +import com.siyeh.ig.psiutils.DeclarationSearchUtils; import com.siyeh.ipp.base.Intention; import com.siyeh.ipp.base.PsiElementPredicate; import org.jetbrains.annotations.NotNull; @@ -71,7 +71,7 @@ public class ConvertCatchToThrowsIntention extends Intention { return; } final PsiCodeBlock parentCodeBlock = PsiTreeUtil.getParentOfType(tryStatement, PsiCodeBlock.class); - if (parentCodeBlock == null || !VariableSearchUtils.containsConflictingDeclarations(tryBlock, parentCodeBlock)) { + if (parentCodeBlock == null || !DeclarationSearchUtils.containsConflictingDeclarations(tryBlock, parentCodeBlock)) { final PsiElement first = tryBlock.getFirstBodyElement(); final PsiElement last = tryBlock.getLastBodyElement(); if (first != null && last != null) { From 01c9c0da5cc32d5b59881492aa57294481ebf4af Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Mon, 4 Jul 2016 13:54:43 +0200 Subject: [PATCH 22/50] IG: remove some duplication --- ...eclareCollectionAsInterfaceInspection.java | 26 +++---------------- ...ethodOnlyUsedFromInnerClassInspection.java | 20 ++++---------- ...ethodOnlyUsedInOneClassInspectionBase.java | 14 +++------- .../ig/psiutils/DeclarationSearchUtils.java | 25 +++++++++++++++++- 4 files changed, 37 insertions(+), 48 deletions(-) diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/abstraction/DeclareCollectionAsInterfaceInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/abstraction/DeclareCollectionAsInterfaceInspection.java index ea878cda2318..9fa145243c78 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/abstraction/DeclareCollectionAsInterfaceInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/abstraction/DeclareCollectionAsInterfaceInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2014 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2016 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,19 +17,16 @@ package com.siyeh.ig.abstraction; import com.intellij.codeInspection.ProblemDescriptor; import com.intellij.codeInspection.ui.MultipleCheckboxOptionsPanel; -import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.codeStyle.JavaCodeStyleManager; -import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.search.PsiSearchHelper; -import com.intellij.psi.search.SearchScope; import com.intellij.util.IncorrectOperationException; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; import com.siyeh.ig.BaseInspectionVisitor; import com.siyeh.ig.InspectionGadgetsFix; import com.siyeh.ig.psiutils.CollectionUtils; +import com.siyeh.ig.psiutils.DeclarationSearchUtils; import com.siyeh.ig.psiutils.LibraryUtil; import com.siyeh.ig.psiutils.WeakestTypeFinder; import org.jetbrains.annotations.NotNull; @@ -146,7 +143,7 @@ public class DeclareCollectionAsInterfaceInspection extends BaseInspection { @Override public void visitVariable(@NotNull PsiVariable variable) { - if (isOnTheFly() && !isCheapEnoughToSearch(variable)) { + if (isOnTheFly() && DeclarationSearchUtils.isTooExpensiveToSearch(variable, false)) { return; } if (ignoreLocalVariables && variable instanceof PsiLocalVariable) { @@ -189,7 +186,7 @@ public class DeclareCollectionAsInterfaceInspection extends BaseInspection { method.hasModifierProperty(PsiModifier.PRIVATE)) { return; } - if (isOnTheFly() && !isCheapEnoughToSearch(method)) { + if (isOnTheFly() && DeclarationSearchUtils.isTooExpensiveToSearch(method, false)) { return; } final PsiType type = method.getReturnType(); @@ -234,20 +231,5 @@ public class DeclareCollectionAsInterfaceInspection extends BaseInspection { registerError(nameElement, qualifiedName); } } - - private boolean isCheapEnoughToSearch(PsiNamedElement element) { - final String name = element.getName(); - if (name == null) { - return false; - } - final ProgressManager progressManager = - ProgressManager.getInstance(); - final PsiSearchHelper searchHelper = PsiSearchHelper.SERVICE.getInstance(element.getProject()); - final SearchScope useScope = element.getUseScope(); - if (useScope instanceof GlobalSearchScope) { - return searchHelper.isCheapEnoughToSearch(name, (GlobalSearchScope)useScope, null, progressManager.getProgressIndicator()) != PsiSearchHelper.SearchCostResult.TOO_MANY_OCCURRENCES; - } - return true; - } } } \ No newline at end of file diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/abstraction/MethodOnlyUsedFromInnerClassInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/abstraction/MethodOnlyUsedFromInnerClassInspection.java index 1286843309cf..e43e5bb69aa6 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/abstraction/MethodOnlyUsedFromInnerClassInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/abstraction/MethodOnlyUsedFromInnerClassInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2005-2012 Bas Leijdekkers + * Copyright 2005-2016 Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,18 +16,15 @@ package com.siyeh.ig.abstraction; import com.intellij.codeInspection.ui.MultipleCheckboxOptionsPanel; -import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.progress.ProgressManager; import com.intellij.psi.*; -import com.intellij.psi.search.PsiSearchHelper; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.Processor; -import com.intellij.util.Query; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; import com.siyeh.ig.BaseInspectionVisitor; import com.siyeh.ig.psiutils.ClassUtils; +import com.siyeh.ig.psiutils.DeclarationSearchUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -182,17 +179,10 @@ public class MethodOnlyUsedFromInnerClassInspection extends BaseInspection { } public boolean isOnlyAccessedFromInnerClass() { - final PsiSearchHelper searchHelper = PsiSearchHelper.SERVICE.getInstance(method.getProject()); - final ProgressManager progressManager = ProgressManager.getInstance(); - final ProgressIndicator progressIndicator = progressManager.getProgressIndicator(); - final PsiSearchHelper.SearchCostResult searchCost = - searchHelper.isCheapEnoughToSearch(method.getName(), method.getResolveScope(), null, progressIndicator); - if (searchCost == PsiSearchHelper.SearchCostResult.TOO_MANY_OCCURRENCES || - searchCost == PsiSearchHelper.SearchCostResult.ZERO_OCCURRENCES) { - return onlyAccessedFromInnerClass; + if (DeclarationSearchUtils.isTooExpensiveToSearch(method, true)) { + return false; } - final Query query = ReferencesSearch.search(method); - query.forEach(this); + ReferencesSearch.search(method).forEach(this); return onlyAccessedFromInnerClass; } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/abstraction/StaticMethodOnlyUsedInOneClassInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/abstraction/StaticMethodOnlyUsedInOneClassInspectionBase.java index 9d10a449ec4c..52dcdc9ad1f1 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/abstraction/StaticMethodOnlyUsedInOneClassInspectionBase.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/abstraction/StaticMethodOnlyUsedInOneClassInspectionBase.java @@ -18,9 +18,7 @@ package com.siyeh.ig.abstraction; import com.intellij.codeInspection.ui.MultipleCheckboxOptionsPanel; import com.intellij.openapi.progress.ProgressManager; import com.intellij.psi.*; -import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.PsiElementProcessor; -import com.intellij.psi.search.PsiSearchHelper; import com.intellij.psi.search.searches.MethodReferencesSearch; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; @@ -30,6 +28,7 @@ import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; import com.siyeh.ig.BaseInspectionVisitor; import com.siyeh.ig.psiutils.ClassUtils; +import com.siyeh.ig.psiutils.DeclarationSearchUtils; import com.siyeh.ig.psiutils.TestUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -110,17 +109,12 @@ public class StaticMethodOnlyUsedInOneClassInspectionBase extends BaseInspection */ @Nullable public PsiClass getUsageClass(final PsiMethod method) { - final ProgressManager progressManager = ProgressManager.getInstance(); - final PsiSearchHelper searchHelper = PsiSearchHelper.SERVICE.getInstance(method.getProject()); - final String name = method.getName(); - final GlobalSearchScope scope = GlobalSearchScope.projectScope(method.getProject()); - if (searchHelper.isCheapEnoughToSearch(name, scope, null, progressManager.getProgressIndicator()) - == PsiSearchHelper.SearchCostResult.TOO_MANY_OCCURRENCES) { + if (DeclarationSearchUtils.isTooExpensiveToSearch(method, true)) { return null; } - progressManager.runProcess(() -> { + ProgressManager.getInstance().runProcess(() -> { final Query query = MethodReferencesSearch.search(method); - if (!query.forEach(UsageProcessor.this)) { + if (!query.forEach(this)) { foundClass.set(null); } }, null); diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/DeclarationSearchUtils.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/DeclarationSearchUtils.java index 59547dffdae3..cd7fe1d0cf24 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/DeclarationSearchUtils.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/DeclarationSearchUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2015 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2016 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,9 +15,13 @@ */ package com.siyeh.ig.psiutils; +import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.controlFlow.DefUseUtil; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.search.PsiSearchHelper; +import com.intellij.psi.search.SearchScope; import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -132,4 +136,23 @@ public class DeclarationSearchUtils { } return null; } + + public static boolean isTooExpensiveToSearch(PsiNamedElement element, boolean zeroResult) { + final String name = element.getName(); + if (name == null) { + return true; + } + final ProgressManager progressManager = ProgressManager.getInstance(); + final PsiSearchHelper searchHelper = PsiSearchHelper.SERVICE.getInstance(element.getProject()); + final SearchScope useScope = element.getUseScope(); + if (!(useScope instanceof GlobalSearchScope)) { + return zeroResult; + } + final PsiSearchHelper.SearchCostResult cost = + searchHelper.isCheapEnoughToSearch(name, (GlobalSearchScope)useScope, null, progressManager.getProgressIndicator()); + if (cost == PsiSearchHelper.SearchCostResult.ZERO_OCCURRENCES) { + return zeroResult; + } + return cost == PsiSearchHelper.SearchCostResult.TOO_MANY_OCCURRENCES; + } } \ No newline at end of file From 8ca3ba6c0bfca71e4a7d6ab95a3a2af2665db0d5 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Mon, 4 Jul 2016 13:55:32 +0200 Subject: [PATCH 23/50] IPP: avoid bad intention performance --- .../annotation/AnnotateOverriddenMethodsPredicate.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/annotation/AnnotateOverriddenMethodsPredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/annotation/AnnotateOverriddenMethodsPredicate.java index 64423fe68f51..7f55b54a0343 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/annotation/AnnotateOverriddenMethodsPredicate.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/annotation/AnnotateOverriddenMethodsPredicate.java @@ -1,5 +1,5 @@ /* - * Copyright 20112013 Bas Leijdekkers + * Copyright 2011-2016 Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,15 +16,16 @@ package com.siyeh.ipp.annotation; import com.intellij.codeInsight.AnnotationUtil; -import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.search.searches.OverridingMethodsSearch; +import com.siyeh.ig.psiutils.DeclarationSearchUtils; import com.siyeh.ipp.base.PsiElementPredicate; import java.util.Collection; class AnnotateOverriddenMethodsPredicate implements PsiElementPredicate { + @Override public boolean satisfiedBy(PsiElement element) { if (!(element instanceof PsiAnnotation)) { return false; @@ -64,7 +65,9 @@ class AnnotateOverriddenMethodsPredicate implements PsiElementPredicate { parameterIndex = -1; method = (PsiMethod)grandParent; } - final Project project = element.getProject(); + if (DeclarationSearchUtils.isTooExpensiveToSearch(method, true)) { + return false; + } final Collection overridingMethods = OverridingMethodsSearch.search(method).findAll(); if (overridingMethods.isEmpty()) { From 6d683643a30a14b7bb495fe5f16f47e3e3b348c4 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Mon, 4 Jul 2016 14:01:19 +0200 Subject: [PATCH 24/50] enable js.debugger.map.this.by.source.code by default --- .../script-debugger/debugger-ui/src/ScopeVariablesGroup.kt | 6 +++--- platform/script-debugger/debugger-ui/src/VariablesGroup.kt | 2 +- .../src/com/jetbrains/javascript/debugger/NameMapper.kt | 5 +++-- platform/util/resources/misc/registry.properties | 2 +- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/platform/script-debugger/debugger-ui/src/ScopeVariablesGroup.kt b/platform/script-debugger/debugger-ui/src/ScopeVariablesGroup.kt index 21c77ef18fbf..9b0f5ed3161d 100644 --- a/platform/script-debugger/debugger-ui/src/ScopeVariablesGroup.kt +++ b/platform/script-debugger/debugger-ui/src/ScopeVariablesGroup.kt @@ -44,9 +44,9 @@ class ScopeVariablesGroup(val scope: Scope, parentContext: VariableContext, call promise .done(node) { context.memberFilter - .thenAsyncAccept(node) { memberFilter -> - if (memberFilter.hasNameMappings()) { - memberFilter.sourceNameToRaw(RECEIVER_NAME)?.let { + .thenAsyncAccept(node) { + if (it.hasNameMappings()) { + it.sourceNameToRaw(RECEIVER_NAME)?.let { return@thenAsyncAccept callFrame.evaluateContext.evaluate(it) .done(node) { VariableImpl(RECEIVER_NAME, it.value, null) diff --git a/platform/script-debugger/debugger-ui/src/VariablesGroup.kt b/platform/script-debugger/debugger-ui/src/VariablesGroup.kt index 357e4b8d7a69..8726e4b9f130 100644 --- a/platform/script-debugger/debugger-ui/src/VariablesGroup.kt +++ b/platform/script-debugger/debugger-ui/src/VariablesGroup.kt @@ -29,6 +29,6 @@ internal class VariablesGroup(private val start: Int, private val end: Int, priv } internal fun createArrayRangeGroup(variables: List, start: Int, end: Int, variableContext: VariableContext): VariablesGroup { - val name = "[" + variables[start].name + " \u2026 " + variables[end - 1].name + "]" + val name = "[${variables[start].name} \u2026 ${variables[end - 1].name}]" return VariablesGroup(start, end, variables, variableContext, name) } diff --git a/platform/script-debugger/debugger-ui/src/com/jetbrains/javascript/debugger/NameMapper.kt b/platform/script-debugger/debugger-ui/src/com/jetbrains/javascript/debugger/NameMapper.kt index 556969cf0425..27db8d89a31b 100644 --- a/platform/script-debugger/debugger-ui/src/com/jetbrains/javascript/debugger/NameMapper.kt +++ b/platform/script-debugger/debugger-ui/src/com/jetbrains/javascript/debugger/NameMapper.kt @@ -40,7 +40,8 @@ open class NameMapper(private val document: Document, private val transpiledDocu // PsiNamedElement, JSVariable for example // returns generated name - open fun map(identifierOrNamedElement: PsiElement): String? { + @JvmOverloads + open fun map(identifierOrNamedElement: PsiElement, forceMapBySourceCode: Boolean = false): String? { val offset = identifierOrNamedElement.textOffset val line = document.getLineNumber(offset) @@ -67,7 +68,7 @@ open class NameMapper(private val document: Document, private val transpiledDocu } var sourceName = sourceEntry.name - if (sourceName == null || (Registry.`is`("js.debugger.name.mappings.by.source.code", false) || Registry.`is`("js.debugger.map.this.by.source.code", false))) { + if (sourceName == null || forceMapBySourceCode || Registry.`is`("js.debugger.name.mappings.by.source.code", false)) { sourceName = (identifierOrNamedElement as? PsiNamedElement)?.name ?: identifierOrNamedElement.text ?: sourceName ?: return null } diff --git a/platform/util/resources/misc/registry.properties b/platform/util/resources/misc/registry.properties index 0b8253ec1108..d9a15866356d 100644 --- a/platform/util/resources/misc/registry.properties +++ b/platform/util/resources/misc/registry.properties @@ -605,7 +605,7 @@ js.debugger.v8.use.any.breakpoint=true js.debugger.chrome.use.any.breakpoint=true nodejs.debugger.use.jb.support=true js.debugger.name.mappings.by.source.code=false -js.debugger.map.this.by.source.code=false +js.debugger.map.this.by.source.code=true js.debugger.v8.log= js.debugger.wip.log= js.debugger.fix.jspm.source.maps=false From f445c8b9bf56c73f24396f5ab8679ded0fd1d457 Mon Sep 17 00:00:00 2001 From: Pavel Dolgov Date: Mon, 4 Jul 2016 15:10:01 +0300 Subject: [PATCH 25/50] Java inspection: don't offer "Make Type Generic" quick fix for non-physical elements (IDEA-157727) --- .../miscGenerics/MakeTypeGenericInspection.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/miscGenerics/MakeTypeGenericInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/miscGenerics/MakeTypeGenericInspection.java index 09b86b2fe9e5..80e9800921c2 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/miscGenerics/MakeTypeGenericInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/miscGenerics/MakeTypeGenericInspection.java @@ -37,17 +37,16 @@ public class MakeTypeGenericInspection extends BaseJavaBatchLocalInspectionTool @Override public void visitVariable(PsiVariable variable) { super.visitVariable(variable); - if (variable.getTypeElement() != null) { + final PsiTypeElement variableTypeElement = variable.getTypeElement(); + if (variableTypeElement != null && variableTypeElement.isPhysical()) { final PsiType type = getSuggestedType(variable); if (type != null) { final String typeText = type.getCanonicalText(); - final String message = - InspectionsBundle.message("inspection.raw.variable.type.make.generic.text", variable.getName(), typeText); - final PsiElement beforeInitializer = - PsiTreeUtil.skipSiblingsBackward(variable.getInitializer(), PsiWhiteSpace.class, PsiComment.class); + final String message = InspectionsBundle.message("inspection.raw.variable.type.make.generic.text", variable.getName(), typeText); + final PsiElement beforeInitializer = PsiTreeUtil.skipSiblingsBackward(variable.getInitializer(), PsiWhiteSpace.class, PsiComment.class); + final PsiElement endElement = beforeInitializer != null && beforeInitializer.isPhysical() ? beforeInitializer : variableTypeElement; final ProblemDescriptor descriptor = - holder.getManager().createProblemDescriptor(variable.getTypeElement(), - beforeInitializer != null ? beforeInitializer : variable.getTypeElement(), + holder.getManager().createProblemDescriptor(variableTypeElement, endElement, message, ProblemHighlightType.GENERIC_ERROR_OR_WARNING, isOnTheFly, new MyLocalQuickFix(message)); holder.registerProblem(descriptor); From 64b96da1d9e719e05e08e4fc88e6ee69e81d4db2 Mon Sep 17 00:00:00 2001 From: Pavel Dolgov Date: Mon, 4 Jul 2016 15:22:45 +0300 Subject: [PATCH 26/50] Java inspection: After removal of AddOverrideAnnotationAction remove related i18 messages as well. (IDEA-157727) --- .../src/messages/CodeInsightBundle.properties | 2 -- 1 file changed, 2 deletions(-) diff --git a/platform/platform-resources-en/src/messages/CodeInsightBundle.properties b/platform/platform-resources-en/src/messages/CodeInsightBundle.properties index 4f4c29ff3ce9..18d187c8a2bf 100644 --- a/platform/platform-resources-en/src/messages/CodeInsightBundle.properties +++ b/platform/platform-resources-en/src/messages/CodeInsightBundle.properties @@ -168,8 +168,6 @@ intention.join.declaration.family=Join Declaration and Assignment intention.split.declaration.text=Split into separate declarations intention.join.declaration.text=Join declaration and assignment intention.split.declaration.assignment.text=Split into declaration and assignment -intention.add.override.annotation=Add '@Override' annotation -intention.add.override.annotation.family=Add Override Annotation intention.split.if.family=Split If intention.split.if.text=Split into 2 if's intention.split.filter.text=Split into filter's chain From 9f3ffa0619dadc49aa39175752ba560c53859a46 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Mon, 4 Jul 2016 14:35:47 +0300 Subject: [PATCH 27/50] diff: update foldings in a single batch operation This fixes completion popup blinking on typing If we destroy and install foldings in separate operaions, caret's visual position jumps back and forth, triggering popup close --- .../diff/tools/simple/SimpleDiffViewer.java | 5 ++- .../simple/ThreesideTextDiffViewerEx.java | 3 +- .../diff/tools/util/FoldingModelSupport.java | 38 +++++++++++-------- 3 files changed, 28 insertions(+), 18 deletions(-) diff --git a/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleDiffViewer.java b/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleDiffViewer.java index f45d82dc53ed..7577e69532e7 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleDiffViewer.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleDiffViewer.java @@ -99,6 +99,7 @@ public class SimpleDiffViewer extends TwosideTextDiffViewer { @CalledInAwt protected void onDispose() { destroyChangedBlocks(); + myFoldingModel.destroy(); super.onDispose(); } @@ -225,6 +226,7 @@ public class SimpleDiffViewer extends TwosideTextDiffViewer { private Runnable apply(@NotNull final CompareData data) { return () -> { myFoldingModel.updateContext(myRequest, getFoldingModelSettings()); + clearDiffPresentation(); myIsContentsEqual = data.isContentsEqual(); @@ -253,6 +255,7 @@ public class SimpleDiffViewer extends TwosideTextDiffViewer { private Runnable applyNotification(@Nullable final JComponent notification) { return () -> { clearDiffPresentation(); + myFoldingModel.destroy(); if (notification != null) myPanel.addNotification(notification); }; } @@ -290,8 +293,6 @@ public class SimpleDiffViewer extends TwosideTextDiffViewer { } myInvalidDiffChanges.clear(); - myFoldingModel.destroy(); - myContentPanel.repaintDivider(); myStatusPanel.update(); } diff --git a/platform/diff-impl/src/com/intellij/diff/tools/simple/ThreesideTextDiffViewerEx.java b/platform/diff-impl/src/com/intellij/diff/tools/simple/ThreesideTextDiffViewerEx.java index 8a413b1b7e21..a8cb44402d44 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/simple/ThreesideTextDiffViewerEx.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/simple/ThreesideTextDiffViewerEx.java @@ -88,6 +88,7 @@ public abstract class ThreesideTextDiffViewerEx extends ThreesideTextDiffViewer @CalledInAwt protected void onDispose() { destroyChangedBlocks(); + myFoldingModel.destroy(); super.onDispose(); } @@ -119,6 +120,7 @@ public abstract class ThreesideTextDiffViewerEx extends ThreesideTextDiffViewer protected Runnable applyNotification(@Nullable final JComponent notification) { return () -> { clearDiffPresentation(); + myFoldingModel.destroy(); if (notification != null) myPanel.addNotification(notification); }; } @@ -135,7 +137,6 @@ public abstract class ThreesideTextDiffViewerEx extends ThreesideTextDiffViewer @CalledInAwt protected void destroyChangedBlocks() { - myFoldingModel.destroy(); } // diff --git a/platform/diff-impl/src/com/intellij/diff/tools/util/FoldingModelSupport.java b/platform/diff-impl/src/com/intellij/diff/tools/util/FoldingModelSupport.java index f81d6f159692..4d1ef04bcaf9 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/util/FoldingModelSupport.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/util/FoldingModelSupport.java @@ -100,12 +100,21 @@ public class FoldingModelSupport { @NotNull final Settings settings) { ApplicationManager.getApplication().assertIsDispatchThread(); - if (changedLines == null) return; - if (settings.range == -1) return; + for (FoldedBlock folding : getFoldedBlocks()) { + folding.destroyHighlighter(); + } runBatchOperation(() -> { - FoldingBuilder builder = new FoldingBuilder(context, settings); - builder.build(changedLines); + for (FoldedBlock folding : getFoldedBlocks()) { + folding.destroyFolding(); + } + myFoldings.clear(); + + + if (changedLines != null && settings.range != -1) { + FoldingBuilder builder = new FoldingBuilder(context, settings); + builder.build(changedLines); + } }); updateLineNumbers(true); @@ -244,23 +253,15 @@ public class FoldingModelSupport { } public void destroy() { - for (int i = 0; i < myCount; i++) { - destroyFoldings(i); - } - for (FoldedBlock folding : getFoldedBlocks()) { folding.destroyHighlighter(); } - myFoldings.clear(); - } - private void destroyFoldings(final int index) { - final FoldingModelEx model = myEditors[index].getFoldingModel(); - model.runBatchFoldingOperation(() -> { + runBatchOperation(() -> { for (FoldedBlock folding : getFoldedBlocks()) { - FoldRegion region = folding.getRegion(index); - if (region != null) model.removeFoldRegion(region); + folding.destroyFolding(); } + myFoldings.clear(); }); } @@ -615,6 +616,13 @@ public class FoldingModelSupport { } } + public void destroyFolding() { + for (int i = 0; i < myCount; i++) { + FoldRegion region = myRegions[i]; + if (region != null) myEditors[i].getFoldingModel().removeFoldRegion(region); + } + } + public void destroyHighlighter() { for (RangeHighlighter highlighter : myHighlighters) { highlighter.dispose(); From a068d9a88182388d72ef68c71e1de776bc258828 Mon Sep 17 00:00:00 2001 From: Dmitry Batrak Date: Fri, 1 Jul 2016 20:20:45 +0300 Subject: [PATCH 28/50] Do not put IDE fatal errors into Event Log, there's a dedicated UI for them --- .../src/com/intellij/diagnostic/DefaultIdeaErrorLogger.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/diagnostic/DefaultIdeaErrorLogger.java b/platform/platform-impl/src/com/intellij/diagnostic/DefaultIdeaErrorLogger.java index 9a72786c4f3a..ba429ca53cbc 100644 --- a/platform/platform-impl/src/com/intellij/diagnostic/DefaultIdeaErrorLogger.java +++ b/platform/platform-impl/src/com/intellij/diagnostic/DefaultIdeaErrorLogger.java @@ -88,10 +88,7 @@ public class DefaultIdeaErrorLogger implements ErrorLogger { } else if (!ourOomOccurred) { MessagePool messagePool = MessagePool.getInstance(); - LogMessage message = messagePool.addIdeFatalMessage(event); - if (message != null && ApplicationManager.getApplication() != null) { - ErrorNotifier.notifyUi(message, messagePool); - } + messagePool.addIdeFatalMessage(event); } } catch (Throwable e) { From 1ad27e63db8d3b9012003278c210a29b23290134 Mon Sep 17 00:00:00 2001 From: Dmitry Batrak Date: Mon, 4 Jul 2016 11:16:25 +0300 Subject: [PATCH 29/50] Do not include information about submitting error report by default in Event Log by default, remove unused class --- .../intellij/diagnostic/ErrorNotifier.java | 102 ------------------ .../intellij/diagnostic/ReportMessages.java | 2 +- 2 files changed, 1 insertion(+), 103 deletions(-) delete mode 100644 platform/platform-impl/src/com/intellij/diagnostic/ErrorNotifier.java diff --git a/platform/platform-impl/src/com/intellij/diagnostic/ErrorNotifier.java b/platform/platform-impl/src/com/intellij/diagnostic/ErrorNotifier.java deleted file mode 100644 index acc25247f9dd..000000000000 --- a/platform/platform-impl/src/com/intellij/diagnostic/ErrorNotifier.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2000-2012 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.diagnostic; - -import com.intellij.notification.Notification; -import com.intellij.notification.NotificationGroup; -import com.intellij.notification.NotificationListener; -import com.intellij.notification.NotificationType; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.wm.IdeFrame; -import com.intellij.openapi.wm.StatusBar; -import com.intellij.openapi.wm.StatusBarWidget; -import org.jetbrains.annotations.NotNull; - -import javax.swing.*; -import javax.swing.event.HyperlinkEvent; -import java.awt.*; - -/** - * @author peter - */ -public class ErrorNotifier { - private static final NotificationGroup NOTIFICATION_GROUP = NotificationGroup.logOnlyGroup("IDE Fatal Errors"); - - public static void notifyUi(final LogMessage message, final MessagePool pool) { - //noinspection ThrowableResultOfMethodCallIgnored - if (message.getThrowable() instanceof MessagePool.TooManyErrorsException) { - NOTIFICATION_GROUP.createNotification(message.getMessage(), NotificationType.ERROR).notify(null); - return; - } - - String title = "" + getTitle(message) + ""; - String notificationText = getNotificationText(message); - NotificationListener listener = new NotificationListener() { - @Override - public void hyperlinkUpdate(@NotNull Notification notification, @NotNull HyperlinkEvent event) { - if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { - openFatals(event, message); - } - } - }; - Notification notification = new Notification(NOTIFICATION_GROUP.getDisplayId(), title, notificationText, NotificationType.ERROR, listener) { - @Override - public void expire() { - super.expire(); - if (!message.isRead()) { - message.setRead(true); - } - pool.notifyListenersRead(); - } - }; - notification.notify(null); - message.setNotification(notification); - } - - private static void openFatals(HyperlinkEvent event, LogMessage message) { - Object source = event.getSource(); - if (source instanceof Component) { - Window window = SwingUtilities.getWindowAncestor((Component)source); - if (window instanceof IdeFrame) { - final StatusBar statusBar = ((IdeFrame)window).getStatusBar(); - StatusBarWidget widget = statusBar == null ? null : statusBar.getWidget(IdeMessagePanel.FATAL_ERROR); - if (widget instanceof IdeMessagePanel) { - ((IdeMessagePanel)widget).openFatals(message); - } - } - } - } - - private static String getNotificationText(LogMessage message) { - String text = message.getMessage(); - if (message instanceof LogMessageEx) { - String result = ((LogMessageEx)message).getNotificationText(); - if (result != null) { - text = StringUtil.stripHtml(result, false); - } - } - return text; - } - - private static String getTitle(LogMessage message) { - if (message instanceof LogMessageEx) { - return ((LogMessageEx)message).getTitle(); - } - @SuppressWarnings("ThrowableResultOfMethodCallIgnored") Throwable throwable = message.getThrowable(); - return throwable == null ? "IDE Fatal Error" : throwable.getClass().getSimpleName(); - } - -} diff --git a/platform/platform-impl/src/com/intellij/diagnostic/ReportMessages.java b/platform/platform-impl/src/com/intellij/diagnostic/ReportMessages.java index 93098278e507..a7c0df3f03f6 100644 --- a/platform/platform-impl/src/com/intellij/diagnostic/ReportMessages.java +++ b/platform/platform-impl/src/com/intellij/diagnostic/ReportMessages.java @@ -27,5 +27,5 @@ import com.intellij.notification.NotificationGroup; public class ReportMessages { public static final String ERROR_REPORT = DiagnosticBundle.message("error.report.title"); - public static final NotificationGroup GROUP = new NotificationGroup(ERROR_REPORT, NotificationDisplayType.BALLOON, true); + public static final NotificationGroup GROUP = new NotificationGroup(ERROR_REPORT, NotificationDisplayType.BALLOON, false); } From 51cd51c0cbf1b2c8c8d2d0c6c52a6b14d470a7ae Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 4 Jul 2016 15:36:01 +0300 Subject: [PATCH 30/50] don't start INFORMATION inspections e.g. if file belongs to cls --- .../intellij/codeInsight/daemon/impl/ShowIntentionsPass.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ShowIntentionsPass.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ShowIntentionsPass.java index 856683d72c2f..1db33b8ce8c8 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ShowIntentionsPass.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ShowIntentionsPass.java @@ -20,6 +20,7 @@ import com.intellij.codeHighlighting.HighlightDisplayLevel; import com.intellij.codeHighlighting.TextEditorHighlightingPass; import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; import com.intellij.codeInsight.daemon.HighlightDisplayKey; +import com.intellij.codeInsight.daemon.impl.analysis.HighlightingLevelManager; import com.intellij.codeInsight.hint.HintManager; import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.codeInsight.intention.IntentionManager; @@ -311,7 +312,9 @@ public class ShowIntentionsPass extends TextEditorHighlightingPass { } } - collectIntentionsFromDoNotShowLeveledInspections(project, hostFile, psiElement, offset, intentions); + if (HighlightingLevelManager.getInstance(project).shouldInspect(hostFile)) { + collectIntentionsFromDoNotShowLeveledInspections(project, hostFile, psiElement, offset, intentions); + } final int line = hostDocument.getLineNumber(offset); MarkupModelEx model = (MarkupModelEx)DocumentMarkupModel.forDocument(hostDocument, project, true); From d262316e90dda9324cd742c8b5353a5773028069 Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Mon, 4 Jul 2016 14:02:38 +0200 Subject: [PATCH 31/50] NPE (EA-85409, EA-85087) --- .../intellij/util/indexing/containers/ChangeBufferingList.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/util/indexing/containers/ChangeBufferingList.java b/platform/lang-impl/src/com/intellij/util/indexing/containers/ChangeBufferingList.java index 57512fb4fd4d..7e9076282b8e 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/containers/ChangeBufferingList.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/containers/ChangeBufferingList.java @@ -84,10 +84,10 @@ public class ChangeBufferingList implements Cloneable { } public void remove(int value) { + ensureCapacity(1); if (checkSet != null) checkSet.remove(value); RandomAccessIntContainer intContainer = randomAccessContainer; if (intContainer == null) { - ensureCapacity(1); addChange(-value); } else { From 1765913f6f1dff10468f91de3af468f66e9a9d04 Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Mon, 4 Jul 2016 15:01:30 +0200 Subject: [PATCH 32/50] index modification stamp, first iteration --- .../com/intellij/index/IndexTest.groovy | 22 +++++++++++++++++++ .../util/indexing/FileBasedIndexImpl.java | 9 ++++++++ .../util/indexing/MapReduceIndex.java | 8 +++++++ 3 files changed, 39 insertions(+) diff --git a/java/java-tests/testSrc/com/intellij/index/IndexTest.groovy b/java/java-tests/testSrc/com/intellij/index/IndexTest.groovy index d1fd11639587..32ab8e9cdbf7 100644 --- a/java/java-tests/testSrc/com/intellij/index/IndexTest.groovy +++ b/java/java-tests/testSrc/com/intellij/index/IndexTest.groovy @@ -51,6 +51,7 @@ import com.intellij.testFramework.exceptionCases.IllegalArgumentExceptionCase import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase import com.intellij.util.Processor import com.intellij.util.indexing.FileBasedIndex +import com.intellij.util.indexing.FileBasedIndexImpl import com.intellij.util.indexing.MapIndexStorage import com.intellij.util.indexing.StorageException import com.intellij.util.io.* @@ -409,6 +410,27 @@ public class IndexTest extends JavaCodeInsightFixtureTestCase { } } + public void "test no index stamp update when no change"() throws IOException { + final VirtualFile vFile = myFixture.addClass("class Foo {}").getContainingFile().getVirtualFile(); + def stamp = ((FileBasedIndexImpl)FileBasedIndex.instance).getIndexModificationStamp(IdIndex.NAME, project) + + VfsUtil.saveText(vFile, "Foo class") + assertTrue(stamp == ((FileBasedIndexImpl)FileBasedIndex.instance).getIndexModificationStamp(IdIndex.NAME, project)) + + VfsUtil.saveText(vFile, "class Foo2 {}") + assertTrue(stamp != ((FileBasedIndexImpl)FileBasedIndex.instance).getIndexModificationStamp(IdIndex.NAME, project)) + + final Document document = FileDocumentManager.getInstance().getDocument(vFile); + document.setText("Foo2 class") + stamp = ((FileBasedIndexImpl)FileBasedIndex.instance).getIndexModificationStamp(IdIndex.NAME, project) + document.setText("class Foo2") + assertTrue(stamp == ((FileBasedIndexImpl)FileBasedIndex.instance).getIndexModificationStamp(IdIndex.NAME, project)) + + document.setText("Foo3 class"); + PsiDocumentManager.getInstance(project).commitAllDocuments(); + assertTrue(stamp != ((FileBasedIndexImpl)FileBasedIndex.instance).getIndexModificationStamp(IdIndex.NAME, project)) + } + public void "test do not collect stub tree while holding stub elements"() throws IOException { final VirtualFile vFile = myFixture.addClass("class Foo {}").getContainingFile().getVirtualFile(); diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java index ce59608b632b..1d3a8a7bc364 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java @@ -806,6 +806,15 @@ public class FileBasedIndexImpl extends FileBasedIndex { : processValuesInScope(indexId, dataKey, false, filter, idFilter, processor); } + public long getIndexModificationStamp(ID indexId, @NotNull Project project) { + UpdatableIndex index = getState().getIndex(indexId); + if (index instanceof MapReduceIndex) { + ensureUpToDate(indexId, project, GlobalSearchScope.allScope(project)); + return ((MapReduceIndex)index).getModificationStamp(); + } + return -1; + } + public interface IdValueProcessor { /** * @param fileId the id of the file that the value came from diff --git a/platform/lang-impl/src/com/intellij/util/indexing/MapReduceIndex.java b/platform/lang-impl/src/com/intellij/util/indexing/MapReduceIndex.java index 9a324bdbdff7..0252c5e79e03 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/MapReduceIndex.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/MapReduceIndex.java @@ -46,6 +46,7 @@ import java.io.*; import java.nio.charset.Charset; import java.util.*; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantReadWriteLock; @@ -66,6 +67,7 @@ public class MapReduceIndex implements UpdatableIndex myExtension; private final AtomicBoolean myInMemoryMode = new AtomicBoolean(); + private final AtomicLong myModificationStamp = new AtomicLong(); private final TIntObjectHashMap> myInMemoryKeys = new TIntObjectHashMap>(); private PersistentHashMap myContents; @@ -900,6 +902,10 @@ public class MapReduceIndex implements UpdatableIndex { private final int savedInputId; private final @NotNull Map newData; @@ -934,6 +940,7 @@ public class MapReduceIndex implements UpdatableIndex() { @Override public void process(Key key, int inputId) throws StorageException { + myModificationStamp.incrementAndGet(); myStorage.removeAllValues(key, inputId); } }; @@ -941,6 +948,7 @@ public class MapReduceIndex implements UpdatableIndex myAddedKeyProcessor = new MapDiffUpdateData.AddedKeyProcessor() { @Override public void process(Key key, Value value, int inputId) throws StorageException { + myModificationStamp.incrementAndGet(); myStorage.addValue(key, inputId, value); } }; From b9775b56038a220559ae3ae0732e5c313c4d75dd Mon Sep 17 00:00:00 2001 From: "dmitriy.tseyler" Date: Mon, 4 Jul 2016 16:03:01 +0300 Subject: [PATCH 33/50] Make EditorTextField font size big in Presentation mode when font not inherited from swing (cherry picked from commit 261b396) --- .../platform-impl/src/com/intellij/ui/EditorTextField.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/platform/platform-impl/src/com/intellij/ui/EditorTextField.java b/platform/platform-impl/src/com/intellij/ui/EditorTextField.java index 8ca103ce0a7b..8c4c459ba1fa 100644 --- a/platform/platform-impl/src/com/intellij/ui/EditorTextField.java +++ b/platform/platform-impl/src/com/intellij/ui/EditorTextField.java @@ -16,6 +16,7 @@ package com.intellij.ui; import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; +import com.intellij.ide.ui.UISettings; import com.intellij.ide.ui.laf.darcula.ui.DarculaEditorTextFieldBorder; import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.actionSystem.DataProvider; @@ -562,7 +563,10 @@ public class EditorTextField extends NonOpaquePanel implements DocumentListener, if (myInheritSwingFont) { editor.getColorsScheme().setEditorFontName(getFont().getFontName()); editor.getColorsScheme().setEditorFontSize(getFont().getSize()); + return; } + UISettings settings = UISettings.getInstance(); + if (settings.PRESENTATION_MODE) editor.setFontSize(settings.PRESENTATION_MODE_FONT_SIZE); } protected boolean shouldHaveBorder() { From de9d45827514578e60eecb17156881f7b86df1f9 Mon Sep 17 00:00:00 2001 From: Anton Makeev Date: Mon, 4 Jul 2016 15:48:59 +0200 Subject: [PATCH 34/50] CPP-7052 General support for project opened from symlinked directories, including remote debug and path mappings --- .../openapi/roots/ProjectRootUtil.java | 42 +++++ .../ProjectRootUtilSymlinkedFilesTest.java | 147 ++++++++++++++++++ 2 files changed, 189 insertions(+) create mode 100644 platform/platform-impl/src/com/intellij/openapi/roots/ProjectRootUtil.java create mode 100644 platform/platform-tests/testSrc/com/intellij/openapi/roots/ProjectRootUtilSymlinkedFilesTest.java diff --git a/platform/platform-impl/src/com/intellij/openapi/roots/ProjectRootUtil.java b/platform/platform-impl/src/com/intellij/openapi/roots/ProjectRootUtil.java new file mode 100644 index 000000000000..15017802c552 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/openapi/roots/ProjectRootUtil.java @@ -0,0 +1,42 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.roots; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.search.FilenameIndex; +import com.intellij.psi.search.GlobalSearchScope; +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; + +public class ProjectRootUtil { + @NotNull + public static VirtualFile findSymlinkedFileInContent(@NotNull Project project, @NotNull VirtualFile forFile) { + GlobalSearchScope scope = GlobalSearchScope.allScope(project); + + if (scope.contains(forFile)) return forFile; + + Collection projectFiles = + FilenameIndex.getVirtualFilesByName(project, forFile.getName(), true, scope); + + for (VirtualFile eachContentFile : projectFiles) { + if (forFile.equals(eachContentFile.getCanonicalFile())) return eachContentFile; + } + + return forFile; + } +} diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/roots/ProjectRootUtilSymlinkedFilesTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/roots/ProjectRootUtilSymlinkedFilesTest.java new file mode 100644 index 000000000000..54cf9bdfea8e --- /dev/null +++ b/platform/platform-tests/testSrc/com/intellij/openapi/roots/ProjectRootUtilSymlinkedFilesTest.java @@ -0,0 +1,147 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.roots; + +import com.intellij.openapi.application.Result; +import com.intellij.openapi.application.WriteAction; +import com.intellij.openapi.util.SystemInfo; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.io.IoTestUtil; +import com.intellij.openapi.vfs.VfsUtil; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.testFramework.PlatformTestCase; +import com.intellij.testFramework.PsiTestUtil; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.io.IOException; + +public class ProjectRootUtilSymlinkedFilesTest extends PlatformTestCase { + private File myCanonicalDir; + private File myCanonicalFile; + private VirtualFile myCanonicalVFile; + private File myContentDir; + private VirtualFile myContentVDir; + private File myLibraryDir; + private VirtualFile myLibraryVDir; + + @Override + protected boolean shouldRunTest() { + return super.shouldRunTest() && SystemInfo.areSymLinksSupported; + } + + @Override + public void setUp() throws Exception { + super.setUp(); + myCanonicalDir = FileUtil.createTempDirectory("canonical", null); + myCanonicalFile = new File(myCanonicalDir, "foo.txt"); + assertTrue(myCanonicalFile.createNewFile()); + + myCanonicalVFile = VfsUtil.findFileByIoFile(myCanonicalFile, true); + assertNotNull(myCanonicalVFile); + + myContentDir = FileUtil.createTempDirectory("content", null); + myContentVDir = VfsUtil.findFileByIoFile(myContentDir, true); + assertNotNull(myContentVDir); + PsiTestUtil.addContentRoot(getModule(), myContentVDir); + + myLibraryDir = FileUtil.createTempDirectory("library", null); + myLibraryVDir = VfsUtil.findFileByIoFile(myLibraryDir, true); + assertNotNull(myLibraryVDir); + PsiTestUtil.addLibrary(getModule(), myLibraryVDir.getPath()); + } + + public void testNoFilesInContent() throws Exception { + assertEquals(myCanonicalVFile, ProjectRootUtil.findSymlinkedFileInContent(getProject(), myCanonicalVFile)); + } + + public void testLinkedDirInContent() throws Exception { + doTestLinkedDirInProjectRoots(true); + } + + public void testLinkedDirInLibrary() throws Exception { + doTestLinkedDirInProjectRoots(false); + } + + public void doTestLinkedDirInProjectRoots(boolean content) throws Exception { + String linkedPath = (content ? myContentDir : myLibraryDir).getPath() + "/linked"; + IoTestUtil.createSymLink(myCanonicalDir.getPath(), linkedPath, true); + + VirtualFile linkedVFile = VfsUtil.findFileByIoFile(new File(linkedPath, myCanonicalFile.getName()), true); + + assertEquals(linkedVFile, ProjectRootUtil.findSymlinkedFileInContent(getProject(), myCanonicalVFile)); + } + + // not supported + public void _testLinkedFileInSources() throws Exception { + String linkedPath = myContentDir.getPath() + "/linked.txt"; + IoTestUtil.createSymLink(myCanonicalVFile.getPath(), linkedPath, true); + + VirtualFile linkedVFile = VfsUtil.findFileByIoFile(new File(linkedPath), true); + assertEquals(linkedVFile, ProjectRootUtil.findSymlinkedFileInContent(getProject(), myCanonicalVFile)); + } + + public void testFileWithTheSameNotButNotLinked() throws Exception { + new WriteAction() { + @Override + protected void run(@NotNull Result result) throws Throwable { + myContentVDir.createChildData(this, myCanonicalFile.getName()); + } + }.execute(); + + assertEquals(myCanonicalVFile, ProjectRootUtil.findSymlinkedFileInContent(getProject(), myCanonicalVFile)); + } + + public void testWhenSeveralLinkedAlwaysReturnTheSameFile() throws Exception { + String linkedPath1 = myContentDir.getPath() + "/linked1"; + IoTestUtil.createSymLink(myCanonicalDir.getPath(), linkedPath1, true); + VirtualFile linkedVFile1 = VfsUtil.findFileByIoFile(new File(linkedPath1, myCanonicalFile.getName()), true); + assertNotNull(linkedVFile1); + + String linkedPath2 = myContentDir.getPath() + "/linked2"; + IoTestUtil.createSymLink(myCanonicalDir.getPath(), linkedPath2, true); + VirtualFile linkedVFile2 = VfsUtil.findFileByIoFile(new File(linkedPath2, myCanonicalFile.getName()), true); + assertNotNull(linkedVFile2); + + VirtualFile found = ProjectRootUtil.findSymlinkedFileInContent(getProject(), myCanonicalVFile); + assertTrue(found.equals(linkedVFile1) || found.equals(linkedVFile2)); + for(int i = 0; i < 10; i++) { + assertEquals("try: " + i, found, ProjectRootUtil.findSymlinkedFileInContent(getProject(), myCanonicalVFile)); + } + } + + public void testLinkedAndCanonicalUnderContent() throws Exception { + doTestLinkedAndCanonicalUnderRoot(true); + } + + public void testLinkedAndCanonicalUnderLibraryRoot() throws Exception { + doTestLinkedAndCanonicalUnderRoot(false); + } + + private void doTestLinkedAndCanonicalUnderRoot(boolean content) throws InterruptedException, IOException { + String linkedPath = myContentDir.getPath() + "/linked"; + IoTestUtil.createSymLink(myCanonicalDir.getPath(), linkedPath, true); + + VirtualFile linkedVFile = VfsUtil.findFileByIoFile(new File(linkedPath, myCanonicalFile.getName()), true); + assertEquals(linkedVFile, ProjectRootUtil.findSymlinkedFileInContent(getProject(), myCanonicalVFile)); + if(content) { + PsiTestUtil.addContentRoot(getModule(), myCanonicalVFile.getParent()); + } else { + PsiTestUtil.addLibrary(getModule(), myCanonicalVFile.getParent().getPath()); + } + assertEquals(myCanonicalVFile, ProjectRootUtil.findSymlinkedFileInContent(getProject(), myCanonicalVFile)); + } +} From 4fac0ed9aac765a52055d5d47ae96bca88956d52 Mon Sep 17 00:00:00 2001 From: Pavel Dolgov Date: Mon, 4 Jul 2016 16:52:57 +0300 Subject: [PATCH 35/50] Java inspection: don't check for non-physical elements in "Make Type Generic" inspection, it's already done in the inspection infrastructure (IDEA-157727) --- .../miscGenerics/MakeTypeGenericInspection.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/miscGenerics/MakeTypeGenericInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/miscGenerics/MakeTypeGenericInspection.java index 80e9800921c2..60c8a24e3503 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/miscGenerics/MakeTypeGenericInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/miscGenerics/MakeTypeGenericInspection.java @@ -38,15 +38,17 @@ public class MakeTypeGenericInspection extends BaseJavaBatchLocalInspectionTool public void visitVariable(PsiVariable variable) { super.visitVariable(variable); final PsiTypeElement variableTypeElement = variable.getTypeElement(); - if (variableTypeElement != null && variableTypeElement.isPhysical()) { + if (variableTypeElement != null) { final PsiType type = getSuggestedType(variable); if (type != null) { final String typeText = type.getCanonicalText(); - final String message = InspectionsBundle.message("inspection.raw.variable.type.make.generic.text", variable.getName(), typeText); - final PsiElement beforeInitializer = PsiTreeUtil.skipSiblingsBackward(variable.getInitializer(), PsiWhiteSpace.class, PsiComment.class); - final PsiElement endElement = beforeInitializer != null && beforeInitializer.isPhysical() ? beforeInitializer : variableTypeElement; + final String message = + InspectionsBundle.message("inspection.raw.variable.type.make.generic.text", variable.getName(), typeText); + final PsiElement beforeInitializer = + PsiTreeUtil.skipSiblingsBackward(variable.getInitializer(), PsiWhiteSpace.class, PsiComment.class); final ProblemDescriptor descriptor = - holder.getManager().createProblemDescriptor(variableTypeElement, endElement, + holder.getManager().createProblemDescriptor(variableTypeElement, + beforeInitializer != null ? beforeInitializer : variableTypeElement, message, ProblemHighlightType.GENERIC_ERROR_OR_WARNING, isOnTheFly, new MyLocalQuickFix(message)); holder.registerProblem(descriptor); From 31c30b108bb0945627d5765845de6fccba3f2acb Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Mon, 4 Jul 2016 17:00:03 +0200 Subject: [PATCH 36/50] honor test generated sources in refresh (IDEA-158088) --- .../com/intellij/compiler/server/BuildManager.java | 10 +++++++--- .../intellij/openapi/compiler/CompilerPaths.java | 14 ++++++++++++-- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java b/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java index e13aab0639d5..4a30867e3aa0 100644 --- a/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java +++ b/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java @@ -1523,9 +1523,13 @@ public class BuildManager implements Disposable { final CompilerConfiguration config = CompilerConfiguration.getInstance(project); for (Module module : compileContext.getCompileScope().getAffectedModules()) { if (config.getAnnotationProcessingConfiguration(module).isEnabled()) { - final String path = CompilerPaths.getAnnotationProcessorsGenerationPath(module); - if (path != null) { - candidates.add(path); + final String productionPath = CompilerPaths.getAnnotationProcessorsGenerationPath(module, false); + if (productionPath != null) { + candidates.add(productionPath); + } + final String testsPath = CompilerPaths.getAnnotationProcessorsGenerationPath(module, true); + if (testsPath != null) { + candidates.add(testsPath); } } } diff --git a/java/compiler/openapi/src/com/intellij/openapi/compiler/CompilerPaths.java b/java/compiler/openapi/src/com/intellij/openapi/compiler/CompilerPaths.java index 1fdd0078e907..3e3a8b086b50 100644 --- a/java/compiler/openapi/src/com/intellij/openapi/compiler/CompilerPaths.java +++ b/java/compiler/openapi/src/com/intellij/openapi/compiler/CompilerPaths.java @@ -176,10 +176,20 @@ public class CompilerPaths { return outPathUrl != null? VirtualFileManager.extractPath(outPathUrl) : null; } + /** + * @return path to annotation-processors generated _production_ sources + Use {@link #getAnnotationProcessorsGenerationPath(Module, boolean)} + */ + @Deprecated @Nullable public static String getAnnotationProcessorsGenerationPath(Module module) { + return getAnnotationProcessorsGenerationPath(module, false); + } + + @Nullable + public static String getAnnotationProcessorsGenerationPath(Module module, boolean forTests) { final AnnotationProcessingConfiguration config = CompilerConfiguration.getInstance(module.getProject()).getAnnotationProcessingConfiguration(module); - final String sourceDirName = config.getGeneratedSourcesDirectoryName(false); + final String sourceDirName = config.getGeneratedSourcesDirectoryName(forTests); if (config.isOutputRelativeToContentRoot()) { final String[] roots = ModuleRootManager.getInstance(module).getContentRootUrls(); if (roots.length == 0) { @@ -192,7 +202,7 @@ public class CompilerPaths { } - final String path = getModuleOutputPath(module, false); + final String path = getModuleOutputPath(module, forTests); if (path == null) { return null; } From 7019abee2e7e5ef8fcdc750dc7a919599ca5dce5 Mon Sep 17 00:00:00 2001 From: irengrig Date: Mon, 4 Jul 2016 17:18:36 +0200 Subject: [PATCH 37/50] WEB-22184 angular-ui-router: UnsupportedOperationException when press cmd+d - fix review comments and bug: IDEA-158003 Compare Files no longer works with files in archives (jar, zip) --- .../vfs/VirtualFileWithoutContent.java | 22 +++++++++++++++++++ .../diff/actions/BaseShowDiffAction.java | 6 +++++ .../actions/CompareFileWithEditorAction.java | 2 +- .../diff/actions/CompareFilesAction.java | 8 ++----- .../editor/ResourceBundleAsVirtualFile.java | 4 ++-- 5 files changed, 33 insertions(+), 9 deletions(-) create mode 100644 platform/core-api/src/com/intellij/openapi/vfs/VirtualFileWithoutContent.java diff --git a/platform/core-api/src/com/intellij/openapi/vfs/VirtualFileWithoutContent.java b/platform/core-api/src/com/intellij/openapi/vfs/VirtualFileWithoutContent.java new file mode 100644 index 000000000000..2651966568e4 --- /dev/null +++ b/platform/core-api/src/com/intellij/openapi/vfs/VirtualFileWithoutContent.java @@ -0,0 +1,22 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.vfs; + +/** + * @author Irina.Chernushina on 7/4/2016. + */ +public interface VirtualFileWithoutContent { +} diff --git a/platform/diff-impl/src/com/intellij/diff/actions/BaseShowDiffAction.java b/platform/diff-impl/src/com/intellij/diff/actions/BaseShowDiffAction.java index 4f3a3627bf78..e918a207063e 100644 --- a/platform/diff-impl/src/com/intellij/diff/actions/BaseShowDiffAction.java +++ b/platform/diff-impl/src/com/intellij/diff/actions/BaseShowDiffAction.java @@ -23,6 +23,8 @@ import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.VirtualFileWithoutContent; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -48,6 +50,10 @@ abstract class BaseShowDiffAction extends AnAction implements DumbAware { protected abstract boolean isAvailable(@NotNull AnActionEvent e); + protected static boolean hasContent(VirtualFile file) { + return ! (file instanceof VirtualFileWithoutContent); + } + @Nullable protected abstract DiffRequest getDiffRequest(@NotNull AnActionEvent e); } diff --git a/platform/diff-impl/src/com/intellij/diff/actions/CompareFileWithEditorAction.java b/platform/diff-impl/src/com/intellij/diff/actions/CompareFileWithEditorAction.java index bbaa285236a1..7f27f7ff45b4 100644 --- a/platform/diff-impl/src/com/intellij/diff/actions/CompareFileWithEditorAction.java +++ b/platform/diff-impl/src/com/intellij/diff/actions/CompareFileWithEditorAction.java @@ -72,7 +72,7 @@ public class CompareFileWithEditorAction extends BaseShowDiffAction { } private static boolean canCompare(@NotNull VirtualFile file1, @NotNull VirtualFile file2) { - return file1.isValid() && file2.isValid() && !file1.equals(file2); + return file1.isValid() && file2.isValid() && !file1.equals(file2) && hasContent(file1) && hasContent(file2); } @Nullable diff --git a/platform/diff-impl/src/com/intellij/diff/actions/CompareFilesAction.java b/platform/diff-impl/src/com/intellij/diff/actions/CompareFilesAction.java index 39f47ddda532..6ac2e1f4a63c 100644 --- a/platform/diff-impl/src/com/intellij/diff/actions/CompareFilesAction.java +++ b/platform/diff-impl/src/com/intellij/diff/actions/CompareFilesAction.java @@ -83,20 +83,16 @@ public class CompareFilesAction extends BaseShowDiffAction { } if (files.length == 1) { - return isValidAndLocal(files[0]); + return hasContent(files[0]); } else if (files.length == 2) { - return isValidAndLocal(files[0]) && isValidAndLocal(files[1]); + return hasContent(files[0]) && hasContent(files[1]); } else { return false; } } - private static boolean isValidAndLocal(VirtualFile file) { - return file.isValid() && file.isInLocalFileSystem(); - } - @Nullable @Override protected DiffRequest getDiffRequest(@NotNull AnActionEvent e) { diff --git a/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleAsVirtualFile.java b/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleAsVirtualFile.java index bfc20426a5d0..26f83ecd2f76 100644 --- a/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleAsVirtualFile.java +++ b/plugins/properties/src/com/intellij/lang/properties/editor/ResourceBundleAsVirtualFile.java @@ -22,8 +22,8 @@ import com.intellij.lang.properties.psi.PropertiesFile; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileSystem; +import com.intellij.openapi.vfs.VirtualFileWithoutContent; import com.intellij.openapi.vfs.newvfs.RefreshQueue; -import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; @@ -36,7 +36,7 @@ import java.util.List; * @author Alexey */ @Presentation(icon = "AllIcons.Nodes.ResourceBundle") -public class ResourceBundleAsVirtualFile extends VirtualFile { +public class ResourceBundleAsVirtualFile extends VirtualFile implements VirtualFileWithoutContent { private final ResourceBundle myResourceBundle; public ResourceBundleAsVirtualFile(@NotNull final ResourceBundle resourceBundle) { From 8b6c1bc21c7d503e8cd69d8a772fda0b42727af2 Mon Sep 17 00:00:00 2001 From: Alexey Utkin Date: Mon, 4 Jul 2016 18:00:32 +0300 Subject: [PATCH 38/50] CPP-7113 Support related per-variable highlighting semantic in Doxigen --- .../fixtures/CodeInsightTestFixture.java | 2 + .../impl/CodeInsightTestFixtureImpl.java | 50 +++++++++++++++++-- 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightTestFixture.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightTestFixture.java index a421c078f493..c3afcddbc9d8 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightTestFixture.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightTestFixture.java @@ -537,6 +537,8 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture { void testFoldingWithCollapseStatus(@NotNull String fileName); + void testRainbow(@NotNull String fileName, @NotNull String text, boolean isRainbowOn, boolean withColor); + void assertPreferredCompletionItems(int selected, @NotNull String... expected); /** diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java index 2bd3161e69e7..ec06caef30ec 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java @@ -16,6 +16,7 @@ package com.intellij.testFramework.fixtures.impl; import com.intellij.analysis.AnalysisScope; +import com.intellij.codeHighlighting.RainbowHighlighter; import com.intellij.codeInsight.TargetElementUtil; import com.intellij.codeInsight.completion.CodeCompletionHandlerBase; import com.intellij.codeInsight.completion.CompletionProgressIndicator; @@ -70,6 +71,7 @@ import com.intellij.openapi.editor.ex.util.EditorUtil; import com.intellij.openapi.editor.impl.DocumentImpl; import com.intellij.openapi.editor.impl.DocumentMarkupModel; import com.intellij.openapi.editor.markup.RangeHighlighter; +import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.openapi.extensions.ExtensionPoint; import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.openapi.extensions.ExtensionsArea; @@ -83,6 +85,8 @@ import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.*; import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.registry.Registry; +import com.intellij.openapi.util.registry.RegistryValue; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.*; import com.intellij.profile.Profile; @@ -133,6 +137,7 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig private static final String START_FOLD = ""; private static final String END_FOLD = ""; + private static final String RAINBOW = "rainbow"; private final IdeaProjectTestFixture myProjectFixture; private final TempDirTestFixture myTempDirFixture; @@ -966,7 +971,7 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig Assert.assertNotNull("Cannot find handler for: " + targetElement, handler); final PsiElement[] psiElements = ArrayUtil.mergeArrays(handler.getPrimaryElements(), handler.getSecondaryElements()); final FindUsagesOptions options = handler.getFindUsagesOptions(null); - if (scope != null) options.searchScope = scope; + if (scope != null) options.searchScope = scope; for (PsiElement psiElement : psiElements) { handler.processElementUsages(psiElement, processor, options); } @@ -1441,7 +1446,7 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig private PsiFile configureByFileInner(@NotNull VirtualFile copy) { return configureInner(copy, SelectionAndCaretMarkupLoader.fromFile(copy)); } - + private PsiFile configureInner(@NotNull final VirtualFile copy, @NotNull final SelectionAndCaretMarkupLoader loader) { assertInitialized(); @@ -1750,17 +1755,35 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig } @NotNull - public String getHighlightingDescription(@NotNull List highlighting, @NotNull String tagName) { + public String getHighlightingDescription(@NotNull List highlighting, @NotNull String tagName, boolean withColor) { final List borders = new LinkedList(); for (HighlightInfo region : highlighting) { - borders.add(new Border(Border.LEFT, region.getStartOffset(), "", false)); + TextAttributes attributes = region.getTextAttributes(null, null); + borders.add(new Border(Border.LEFT, region.getStartOffset(), + attributes == null ? "null" + : attributes.getForegroundColor() == null + ? "null" + : Integer.toHexString(attributes.getForegroundColor().getRGB()), + false)); borders.add(new Border(Border.RIGHT, region.getEndOffset(), "", false)); } Collections.sort(borders); StringBuilder result = new StringBuilder(myEditor.getDocument().getText()); for (Border border : borders) { - result.insert(border.getOffset(), (border.isSide() == Border.LEFT ? "<": ""); + StringBuilder info = new StringBuilder(); + info.append('<'); + if (border.isSide() == Border.LEFT) { + info.append(tagName); + if (withColor) { + info.append(" color=\'").append(border.myText).append('\''); + } + } + else { + info.append('/').append(tagName); + } + info.append('>'); + result.insert(border.getOffset(), info); } return result.toString(); @@ -1809,6 +1832,23 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig testFoldingRegions(verificationFileName, null, false); } + @Override + public void testRainbow(@NotNull String fileName, @NotNull String text, boolean isRainbowOn, boolean withColor) { + RegistryValue registryValue = Registry.get("editor.rainbow.identifiers"); + final boolean rainbowColors = registryValue.asBoolean(); + try { + registryValue.setValue(isRainbowOn); + configureByText(fileName, text.replaceAll("<" + RAINBOW + "(\\scolor=\'[^\']*\')?>", "").replace("", "")); + + Assert.assertEquals(text, getHighlightingDescription(ContainerUtil.filter(doHighlighting(), + info -> info.type == RainbowHighlighter.RAINBOW_ELEMENT), RAINBOW, + withColor)); + } + finally { + registryValue.setValue(rainbowColors); + } + } + @Override public void assertPreferredCompletionItems(final int selected, @NotNull final String... expected) { final LookupImpl lookup = getLookup(); From d088af3662b4187ecada3a886efd76376c1b1e2d Mon Sep 17 00:00:00 2001 From: irengrig Date: Mon, 4 Jul 2016 17:39:10 +0200 Subject: [PATCH 39/50] EA-83091 - IAE: ConcurrentHashSet.add --- .../jetbrains/jsonSchema/impl/JsonSchemaServiceImpl.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaServiceImpl.java b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaServiceImpl.java index 7abe451f88c3..26562132b5f0 100644 --- a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaServiceImpl.java +++ b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaServiceImpl.java @@ -15,7 +15,6 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.LanguageFileType; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.NullableLazyValue; import com.intellij.openapi.util.Pair; import com.intellij.openapi.vfs.VfsUtil; @@ -99,7 +98,10 @@ public class JsonSchemaServiceImpl implements JsonSchemaServiceEx { for (JsonSchemaProviderFactory factory : factories) { final List providers = factory.getProviders(project); for (JsonSchemaFileProvider provider : providers) { - mySchemaFiles.add(provider.getSchemaFile()); + final VirtualFile schemaFile = provider.getSchemaFile(); + if (schemaFile != null) { + mySchemaFiles.add(schemaFile); + } } } initialized = true; From 4aa24b4ea4b3ea2863675124f3f2e47fb2429432 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Mon, 4 Jul 2016 19:41:08 +0300 Subject: [PATCH 40/50] angular-ui-router: UnsupportedOperationException when press cmd+d follow-up: 7019abe --- .../src/com/intellij/diff/actions/BaseShowDiffAction.java | 2 +- .../intellij/diff/actions/CompareFileWithEditorAction.java | 2 +- .../src/com/intellij/diff/actions/CompareFilesAction.java | 2 +- .../intellij/diff/tools/external/ExternalDiffToolUtil.java | 7 ++++++- .../intellij/diff/tools/holders/BinaryEditorHolder.java | 2 ++ 5 files changed, 11 insertions(+), 4 deletions(-) diff --git a/platform/diff-impl/src/com/intellij/diff/actions/BaseShowDiffAction.java b/platform/diff-impl/src/com/intellij/diff/actions/BaseShowDiffAction.java index e918a207063e..2da043cc5812 100644 --- a/platform/diff-impl/src/com/intellij/diff/actions/BaseShowDiffAction.java +++ b/platform/diff-impl/src/com/intellij/diff/actions/BaseShowDiffAction.java @@ -51,7 +51,7 @@ abstract class BaseShowDiffAction extends AnAction implements DumbAware { protected abstract boolean isAvailable(@NotNull AnActionEvent e); protected static boolean hasContent(VirtualFile file) { - return ! (file instanceof VirtualFileWithoutContent); + return !(file instanceof VirtualFileWithoutContent); } @Nullable diff --git a/platform/diff-impl/src/com/intellij/diff/actions/CompareFileWithEditorAction.java b/platform/diff-impl/src/com/intellij/diff/actions/CompareFileWithEditorAction.java index 7f27f7ff45b4..4c7939552a37 100644 --- a/platform/diff-impl/src/com/intellij/diff/actions/CompareFileWithEditorAction.java +++ b/platform/diff-impl/src/com/intellij/diff/actions/CompareFileWithEditorAction.java @@ -72,7 +72,7 @@ public class CompareFileWithEditorAction extends BaseShowDiffAction { } private static boolean canCompare(@NotNull VirtualFile file1, @NotNull VirtualFile file2) { - return file1.isValid() && file2.isValid() && !file1.equals(file2) && hasContent(file1) && hasContent(file2); + return !file1.equals(file2) && hasContent(file1) && hasContent(file2); } @Nullable diff --git a/platform/diff-impl/src/com/intellij/diff/actions/CompareFilesAction.java b/platform/diff-impl/src/com/intellij/diff/actions/CompareFilesAction.java index 6ac2e1f4a63c..91b51d357f5f 100644 --- a/platform/diff-impl/src/com/intellij/diff/actions/CompareFilesAction.java +++ b/platform/diff-impl/src/com/intellij/diff/actions/CompareFilesAction.java @@ -106,7 +106,7 @@ public class CompareFilesAction extends BaseShowDiffAction { if (data.length == 1) { VirtualFile otherFile = getOtherFile(project, data[0]); if (otherFile == null) return null; - if (!data[0].isValid()) return null; + if (!hasContent(data[0])) return null; return DiffRequestFactory.getInstance().createFromFiles(project, data[0], otherFile); } else { diff --git a/platform/diff-impl/src/com/intellij/diff/tools/external/ExternalDiffToolUtil.java b/platform/diff-impl/src/com/intellij/diff/tools/external/ExternalDiffToolUtil.java index b3434dfd28f3..6dafc46c2e22 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/external/ExternalDiffToolUtil.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/external/ExternalDiffToolUtil.java @@ -34,6 +34,7 @@ import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.VirtualFileWithoutContent; import com.intellij.util.LineSeparator; import com.intellij.util.PathUtil; import com.intellij.util.TimeoutUtil; @@ -56,7 +57,11 @@ public class ExternalDiffToolUtil { public static boolean canCreateFile(@NotNull DiffContent content) { if (content instanceof EmptyContent) return true; if (content instanceof DocumentContent) return true; - if (content instanceof FileContent) return true; + if (content instanceof FileContent) { + VirtualFile file = ((FileContent)content).getFile(); + if (file instanceof VirtualFileWithoutContent) return false; + return true; + } if (content instanceof DirectoryContent) return ((DirectoryContent)content).getFile().isInLocalFileSystem(); return false; } diff --git a/platform/diff-impl/src/com/intellij/diff/tools/holders/BinaryEditorHolder.java b/platform/diff-impl/src/com/intellij/diff/tools/holders/BinaryEditorHolder.java index 0b455181d04b..2f13d0c8b023 100644 --- a/platform/diff-impl/src/com/intellij/diff/tools/holders/BinaryEditorHolder.java +++ b/platform/diff-impl/src/com/intellij/diff/tools/holders/BinaryEditorHolder.java @@ -34,6 +34,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.VirtualFileWithoutContent; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -130,6 +131,7 @@ public class BinaryEditorHolder extends EditorHolder { if (project == null) project = ProjectManager.getInstance().getDefaultProject(); VirtualFile file = ((FileContent)content).getFile(); if (!file.isValid()) return false; + if (file instanceof VirtualFileWithoutContent) return false; return FileEditorProviderManager.getInstance().getProviders(project, file).length != 0; } return false; From a95a5c1afec588a533c6e4d9979a44963b877421 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 4 Jul 2016 19:28:28 +0200 Subject: [PATCH 41/50] "test stub hierarchy" action should find non-indexed classes in files reported as 'covered' --- .../impl/SingleClassHierarchy.java | 13 +++-- .../impl/test/TestStubHierarchyAction.java | 53 +++++++++++++++++-- .../psi/stubsHierarchy/ClassHierarchy.java | 4 ++ 3 files changed, 61 insertions(+), 9 deletions(-) diff --git a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/SingleClassHierarchy.java b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/SingleClassHierarchy.java index e148321511fb..bffe473fee6c 100644 --- a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/SingleClassHierarchy.java +++ b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/SingleClassHierarchy.java @@ -26,6 +26,7 @@ import com.intellij.psi.stubsHierarchy.impl.Symbol.ClassSymbol; import com.intellij.util.containers.ContainerUtil; import org.apache.commons.lang.ArrayUtils; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.Arrays; import java.util.BitSet; @@ -112,13 +113,17 @@ public class SingleClassHierarchy extends ClassHierarchy { @NotNull @Override public SmartClassAnchor[] getDirectSubtypeCandidates(@NotNull PsiClass psiClass) { - VirtualFile vFile = psiClass.getContainingFile().getVirtualFile(); - if (!(vFile instanceof VirtualFileWithId)) return StubClassAnchor.EMPTY_ARRAY; - - SmartClassAnchor anchor = forPsiClass(((VirtualFileWithId)vFile).getId(), psiClass); + SmartClassAnchor anchor = findAnchor(psiClass); return anchor == null ? StubClassAnchor.EMPTY_ARRAY : getDirectSubtypeCandidates(anchor); } + @Override + @Nullable + public SmartClassAnchor findAnchor(@NotNull PsiClass psiClass) { + VirtualFile vFile = psiClass.getContainingFile().getVirtualFile(); + return vFile instanceof VirtualFileWithId ? forPsiClass(((VirtualFileWithId)vFile).getId(), psiClass) : null; + } + @NotNull @Override public SmartClassAnchor[] getDirectSubtypeCandidates(@NotNull SmartClassAnchor anchor) { diff --git a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/test/TestStubHierarchyAction.java b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/test/TestStubHierarchyAction.java index 2e6566479c91..d5af5482bd4f 100644 --- a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/test/TestStubHierarchyAction.java +++ b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/test/TestStubHierarchyAction.java @@ -23,13 +23,22 @@ import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.CommonClassNames; import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiManager; +import com.intellij.psi.PsiTypeParameter; +import com.intellij.psi.impl.source.PsiFileImpl; +import com.intellij.psi.impl.source.PsiFileWithStubSupport; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.stubs.StubElement; +import com.intellij.psi.stubs.StubTree; import com.intellij.psi.stubsHierarchy.ClassHierarchy; import com.intellij.psi.stubsHierarchy.HierarchyService; import com.intellij.psi.stubsHierarchy.SmartClassAnchor; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.MultiMap; +import com.intellij.util.indexing.FileBasedIndex; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -72,14 +81,48 @@ public class TestStubHierarchyAction extends InheritanceAction { } private void compareSupers(ProgressIndicator indicator, MultiMap supers, ClassHierarchy hierarchy) { - List anchors = hierarchy.getCoveredClasses(); - for (int i = 0; i < anchors.size(); i++) { - indicator.setFraction(i * 1.0 / anchors.size()); - SmartClassAnchor anchor = anchors.get(i); - compareSupers(anchor, supers.get(anchor)); + List covered = getCoveredFiles(indicator, hierarchy); + for (int i = 0; i < covered.size(); i++) { + indicator.setFraction(i * 1.0 / covered.size()); + checkFile(supers, hierarchy, covered.get(i)); } } + private void checkFile(MultiMap supers, ClassHierarchy hierarchy, VirtualFile vFile) { + for (StubElement element : getStubTree(vFile).getPlainListFromAllRoots()) { + Object psi = element.getPsi(); + if (psi instanceof PsiClass && !(psi instanceof PsiTypeParameter)) { + SmartClassAnchor anchor = hierarchy.findAnchor((PsiClass)psi); + if (anchor == null) { + throw new AssertionError("Class not indexed: " + psi + " in " + vFile); + } + compareSupers(anchor, supers.get(anchor)); + } + } + } + + @NotNull + private List getCoveredFiles(ProgressIndicator indicator, ClassHierarchy hierarchy) { + GlobalSearchScope allScope = GlobalSearchScope.allScope(myProject); + GlobalSearchScope uncovered = hierarchy.restrictToUncovered(allScope); + List covered = new ArrayList<>(); + FileBasedIndex.getInstance().iterateIndexableFiles(file -> { + if (!file.isDirectory() && allScope.contains(file) && !uncovered.contains(file)) { + covered.add(file); + } + return true; + }, myProject, indicator); + return covered; + } + + @NotNull + private StubTree getStubTree(VirtualFile vFile) { + PsiFileWithStubSupport psiFile = (PsiFileWithStubSupport)PsiManager.getInstance(myProject).findFile(vFile); + assert psiFile != null : "No PSI for " + vFile; + StubTree stubTree = psiFile.getStubTree(); + return stubTree != null ? stubTree : ((PsiFileImpl)psiFile).calcStubTree(); + } + private void compareSupers(final SmartClassAnchor anchor, final Collection superAnchors) { PsiClass subClass = anchor.retrieveClass(myProject); List stubSuperList = ContainerUtil.map(superAnchors, (anchor1) -> anchor1.retrieveClass(myProject)); diff --git a/java/java-indexing-impl/src/com/intellij/psi/stubsHierarchy/ClassHierarchy.java b/java/java-indexing-impl/src/com/intellij/psi/stubsHierarchy/ClassHierarchy.java index 2a2cbcc6d110..00337e7d084e 100644 --- a/java/java-indexing-impl/src/com/intellij/psi/stubsHierarchy/ClassHierarchy.java +++ b/java/java-indexing-impl/src/com/intellij/psi/stubsHierarchy/ClassHierarchy.java @@ -18,6 +18,7 @@ package com.intellij.psi.stubsHierarchy; import com.intellij.psi.PsiClass; import com.intellij.psi.search.GlobalSearchScope; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.List; @@ -43,6 +44,9 @@ public abstract class ClassHierarchy { @NotNull public abstract SmartClassAnchor[] getDirectSubtypeCandidates(@NotNull SmartClassAnchor anchor); + @Nullable + public abstract SmartClassAnchor findAnchor(@NotNull PsiClass psiClass); + /** * @return whether stub hierarchy resolver couldn't determine the super class exactly because there were several possible candidates */ From 8aed1499c784eee3fdb47f68e6560e13ac500926 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 4 Jul 2016 19:31:44 +0200 Subject: [PATCH 42/50] stub hierarchy: reindex when stubs change; mark as such some cases when we can't reliably resolve supers --- .../stubsHierarchy/impl/JavaStubIndexer.java | 11 ++++--- .../psi/stubsHierarchy/impl/StubEnter.java | 16 +++++---- .../psi/stubsHierarchy/impl/Symbol.java | 11 ++++--- .../impl/java/stubs/hierarchy/IndexTree.java | 1 + .../stubs/elements/GrStubFileElementType.java | 3 +- .../psi/stubs/hierarchy/GrStubIndexer.java | 33 ++++++++++++++----- 6 files changed, 50 insertions(+), 25 deletions(-) diff --git a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/JavaStubIndexer.java b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/JavaStubIndexer.java index 616ea7213f3c..5a3c7a8c75fb 100644 --- a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/JavaStubIndexer.java +++ b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/JavaStubIndexer.java @@ -28,6 +28,7 @@ import com.intellij.psi.impl.java.stubs.*; import com.intellij.psi.impl.java.stubs.hierarchy.IndexTree; import com.intellij.psi.impl.java.stubs.hierarchy.IndexTree.*; import com.intellij.psi.impl.java.stubs.impl.PsiClassStubImpl; +import com.intellij.psi.impl.source.JavaFileElementType; import com.intellij.psi.stubs.Stub; import com.intellij.psi.stubs.StubElement; import com.intellij.psi.stubs.StubTree; @@ -47,7 +48,7 @@ public class JavaStubIndexer extends StubHierarchyIndexer { @Override public int getVersion() { - return 0; + return JavaFileElementType.STUB_VERSION + 1; } @Override @@ -95,10 +96,7 @@ public class JavaStubIndexer extends StubHierarchyIndexer { @Nullable private static Decl processMember(StubElement el, Set namesCache) { if (el instanceof PsiClassStubImpl) { - PsiClassStubImpl classStub = (PsiClassStubImpl)el; - if (!classStub.isAnonymousInQualifiedNew()) { - return processClassDecl(classStub, namesCache); - } + return processClassDecl((PsiClassStubImpl)el, namesCache); } ArrayList innerList = new ArrayList(); for (StubElement childElement : el.getChildrenStubs()) { @@ -146,6 +144,9 @@ public class JavaStubIndexer extends StubHierarchyIndexer { } int flags = translateFlags(classStub, accessModifiers); + if (classStub.isAnonymousInQualifiedNew()) { + flags |= IndexTree.SUPERS_UNRESOLVED; + } String[] supers = superList.isEmpty() ? ArrayUtil.EMPTY_STRING_ARRAY : ArrayUtil.toStringArray(superList); Decl[] inners = innerList.isEmpty() ? Decl.EMPTY_ARRAY : innerList.toArray(new Decl[innerList.size()]); return new ClassDecl(classStub.id, flags, classStub.getName(), supers, inners); diff --git a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/StubEnter.java b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/StubEnter.java index 0bc428733c76..dcfbe0373dc6 100644 --- a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/StubEnter.java +++ b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/StubEnter.java @@ -96,10 +96,7 @@ public class StubEnter { } private ClassSymbol classEnter(IndexTree.ClassDecl tree, UnitInfo info, Symbol owner, @QNameId int ownerName, int fileId) { - int flags = checkFlags(tree.myMods, owner); - if (info.getType() == IndexTree.BYTECODE) { - flags |= IndexTree.COMPILED; - } + int flags = checkFlags(tree.myMods, owner, info.getType() == IndexTree.BYTECODE); int name = tree.myName; @QNameId int qname = name == NameEnvironment.NO_NAME || ownerName < 0 ? -1 @@ -155,11 +152,18 @@ public class StubEnter { uncompleted = null; } - public static int checkFlags(long flags, Symbol owner) { + private static int checkFlags(long flags, Symbol owner, boolean compiled) { int mask = 0; if (owner.isClass() && (owner.myOwner.isPackage() || owner.isStatic())) { - if ((flags & (IndexTree.INTERFACE | IndexTree.ENUM | IndexTree.STATIC)) != 0 ) + if ((flags & (IndexTree.INTERFACE | IndexTree.ENUM | IndexTree.STATIC)) != 0) { mask |= IndexTree.STATIC; + } + } + if ((flags & IndexTree.SUPERS_UNRESOLVED) != 0) { + mask |= IndexTree.SUPERS_UNRESOLVED; + } + if (compiled) { + mask |= IndexTree.COMPILED; } return mask; } diff --git a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Symbol.java b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Symbol.java index f996e7c5a489..20f5bb1116c3 100644 --- a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Symbol.java +++ b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Symbol.java @@ -85,7 +85,6 @@ public abstract class Symbol { /** A class for class symbols */ public static class ClassSymbol extends MemberSymbol { - private static final int HIERARCHY_INCOMPLETE = 1 << 20; private static final int CONNECT_STARTED = 1 << 21; public static final ClassSymbol[] EMPTY_ARRAY = new ClassSymbol[0]; @@ -101,8 +100,10 @@ public abstract class Symbol { @CompactArray(QualifiedName.class) Object supers) { super(flags | IndexTree.CLASS, owner, name); this.myAnchorId = anchorId; - this.mySuperClasses = supers; - this.myUnitInfo = unitInfo; + + boolean incomplete = isHierarchyIncomplete(); + this.mySuperClasses = incomplete ? null : supers; + this.myUnitInfo = incomplete ? null : unitInfo; } @Override @@ -150,7 +151,7 @@ public abstract class Symbol { void markHierarchyIncomplete() { setSupers(Collections.emptySet()); - myFlags = BitUtil.set(myFlags, HIERARCHY_INCOMPLETE, true); + myFlags = BitUtil.set(myFlags, IndexTree.SUPERS_UNRESOLVED, true); } void setSupers(Set supers) { @@ -161,7 +162,7 @@ public abstract class Symbol { } boolean isHierarchyIncomplete() { - return BitUtil.isSet(myFlags, HIERARCHY_INCOMPLETE); + return BitUtil.isSet(myFlags, IndexTree.SUPERS_UNRESOLVED); } boolean hasAmbiguousSupers() { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/hierarchy/IndexTree.java b/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/hierarchy/IndexTree.java index 7ec276f72e56..2d8b681f9712 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/hierarchy/IndexTree.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/hierarchy/IndexTree.java @@ -38,6 +38,7 @@ public class IndexTree { public static final int ENUM = 1 << 6; public static final int COMPILED = 1 << 7; public static final int MEMBER = 1 << 8; + public static final int SUPERS_UNRESOLVED = 1 << 9; public static final byte BYTECODE = 0; public static final byte JAVA = 1; diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/stubs/elements/GrStubFileElementType.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/stubs/elements/GrStubFileElementType.java index 5d89f4192665..a773914d594f 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/stubs/elements/GrStubFileElementType.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/stubs/elements/GrStubFileElementType.java @@ -40,6 +40,7 @@ import java.io.IOException; * @author ilyas */ public class GrStubFileElementType extends IStubFileElementType { + public static final int STUB_VERSION = 29; public GrStubFileElementType(Language language) { super(language); @@ -84,7 +85,7 @@ public class GrStubFileElementType extends IStubFileElementType { @Override public int getStubVersion() { - return super.getStubVersion() + 29; + return super.getStubVersion() + STUB_VERSION; } @Override diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/stubs/hierarchy/GrStubIndexer.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/stubs/hierarchy/GrStubIndexer.java index c124aae6cc20..1fd114269fae 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/stubs/hierarchy/GrStubIndexer.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/stubs/hierarchy/GrStubIndexer.java @@ -16,6 +16,7 @@ package org.jetbrains.plugins.groovy.lang.psi.stubs.hierarchy; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiFile; import com.intellij.psi.PsiNameHelper; import com.intellij.psi.impl.java.stubs.hierarchy.IndexTree; import com.intellij.psi.impl.java.stubs.hierarchy.IndexTree.*; @@ -25,22 +26,24 @@ import com.intellij.psi.stubs.StubTree; import com.intellij.psi.stubs.StubTreeBuilder; import com.intellij.psi.stubsHierarchy.StubHierarchyIndexer; import com.intellij.util.ArrayUtil; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.indexing.FileContent; +import com.intellij.util.indexing.FileContentImpl; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.GroovyFileType; +import org.jetbrains.plugins.groovy.extensions.GroovyScriptTypeDetector; import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes; +import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; import org.jetbrains.plugins.groovy.lang.psi.stubs.*; +import org.jetbrains.plugins.groovy.lang.psi.stubs.elements.GrStubFileElementType; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.*; public class GrStubIndexer extends StubHierarchyIndexer { @Override public int getVersion() { - return 0; + return GrStubFileElementType.STUB_VERSION + 1; } @Override @@ -51,6 +54,8 @@ public class GrStubIndexer extends StubHierarchyIndexer { @Nullable @Override public Unit indexFile(@NotNull FileContent content) { + if (!isNormalGroovyFile(((FileContentImpl)content).getPsiFileForPsiDependentIndex())) return null; + Stub stubTree = StubTreeBuilder.buildStubTree(content); if (!(stubTree instanceof GrFileStub)) return null; @@ -70,7 +75,7 @@ public class GrStubIndexer extends StubHierarchyIndexer { } if (el instanceof GrTypeDefinitionStub) { - ClassDecl classDecl = processClassDecl((GrTypeDefinitionStub)el, usedNames); + ClassDecl classDecl = processClassDecl((GrTypeDefinitionStub)el, usedNames, false); if (classDecl != null) { classList.add(classDecl); } @@ -87,10 +92,19 @@ public class GrStubIndexer extends StubHierarchyIndexer { return new Unit(pid, IndexTree.GROOVY, imports, classes); } + private static boolean isNormalGroovyFile(final PsiFile file) { + return file instanceof GroovyFile && !hasSpecialScriptType((GroovyFile)file); + } + + private static boolean hasSpecialScriptType(GroovyFile file) { + return file.isScript() && + ContainerUtil.exists(GroovyScriptTypeDetector.EP_NAME.getExtensions(), detector -> detector.isSpecificScriptFile(file)); + } + @Nullable private static Decl processMember(StubElement el, Set namesCache) { if (el instanceof GrTypeDefinitionStub) { - return processClassDecl((GrTypeDefinitionStub)el, namesCache); + return processClassDecl((GrTypeDefinitionStub)el, namesCache, true); } ArrayList innerList = new ArrayList(); for (StubElement childElement : el.getChildrenStubs()) { @@ -103,7 +117,7 @@ public class GrStubIndexer extends StubHierarchyIndexer { } @Nullable - private static ClassDecl processClassDecl(GrTypeDefinitionStub classStub, Set namesCache) { + private static ClassDecl processClassDecl(GrTypeDefinitionStub classStub, Set namesCache, boolean inner) { ArrayList superList = new ArrayList(); ArrayList innerList = new ArrayList(); if (classStub.isAnonymous()) { @@ -128,6 +142,9 @@ public class GrStubIndexer extends StubHierarchyIndexer { } } int flags = translateFlags(classStub); + if (inner && !superList.isEmpty()) { + flags |= IndexTree.SUPERS_UNRESOLVED; // 'extends' list resolves to classes from the current package first, and those can be in a language unknown to this hierarchy + } String[] supers = superList.isEmpty() ? ArrayUtil.EMPTY_STRING_ARRAY : ArrayUtil.toStringArray(superList); Decl[] inners = innerList.isEmpty() ? Decl.EMPTY_ARRAY : innerList.toArray(new Decl[innerList.size()]); return new ClassDecl(classStub.id, flags, classStub.getName(), supers, inners); From e4a71067cc597f553634bc4b6fefd89790aae40a Mon Sep 17 00:00:00 2001 From: "Vassiliy.Kudryashov" Date: Mon, 4 Jul 2016 20:40:40 +0300 Subject: [PATCH 43/50] IDEA 150645 IntelliJ IDEA License Activation dialog layout v2 (after-review) --- .../application/ex/ApplicationInfoEx.java | 13 +++++ .../application/impl/ApplicationInfoImpl.java | 55 +++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/platform/core-impl/src/com/intellij/openapi/application/ex/ApplicationInfoEx.java b/platform/core-impl/src/com/intellij/openapi/application/ex/ApplicationInfoEx.java index 8e805f91cb41..d0d7b52750bf 100644 --- a/platform/core-impl/src/com/intellij/openapi/application/ex/ApplicationInfoEx.java +++ b/platform/core-impl/src/com/intellij/openapi/application/ex/ApplicationInfoEx.java @@ -114,4 +114,17 @@ public abstract class ApplicationInfoEx extends ApplicationInfo { @Nullable public abstract String getCustomizeIDEWizardStepsProvider(); + + public abstract String getSubscriptionFormId(); + + public abstract String getSubscriptionNewsKey(); + + public abstract String getSubscriptionNewsValue(); + + public abstract String getSubscriptionTipsKey(); + + public abstract boolean areSubscriptionTipsAvailable(); + + @Nullable + public abstract String getSubscriptionAdditionalFormData(); } diff --git a/platform/core-impl/src/com/intellij/openapi/application/impl/ApplicationInfoImpl.java b/platform/core-impl/src/com/intellij/openapi/application/impl/ApplicationInfoImpl.java index 30e81f2b7411..be8d164a98eb 100644 --- a/platform/core-impl/src/com/intellij/openapi/application/impl/ApplicationInfoImpl.java +++ b/platform/core-impl/src/com/intellij/openapi/application/impl/ApplicationInfoImpl.java @@ -112,6 +112,13 @@ public class ApplicationInfoImpl extends ApplicationInfoEx { private String myEvalLicenseUrl = "https://www.jetbrains.com/store/license.html"; private String myKeyConversionUrl = "https://www.jetbrains.com/shop/eform/keys-exchange"; + private String mySubscriptionFormId; + private String mySubscriptionNewsKey; + private String mySubscriptionNewsValue; + private String mySubscriptionTipsKey; + private boolean mySubscriptionTipsAvailable; + private String mySubscriptionAdditionalFormData; + private Rectangle myAboutLogoRect; private static final String IDEA_PATH = "/idea/"; @@ -193,6 +200,14 @@ public class ApplicationInfoImpl extends ApplicationInfoEx { private static final String ATTRIBUTE_KEY_CONVERSION_URL = "key-conversion-url"; private static final String ESSENTIAL_PLUGIN = "essential-plugin"; + private static final String ELEMENT_SUBSCRIPTIONS = "subscriptions"; + private static final String ATTRIBUTE_SUBSCRIPTIONS_FORM_ID = "formid"; + private static final String ATTRIBUTE_SUBSCRIPTIONS_NEWS_KEY = "news-key"; + private static final String ATTRIBUTE_SUBSCRIPTIONS_NEWS_VALUE = "news-value"; + private static final String ATTRIBUTE_SUBSCRIPTIONS_TIPS_KEY = "tips-key"; + private static final String ATTRIBUTE_SUBSCRIPTIONS_TIPS_AVAILABLE = "tips-available"; + private static final String ATTRIBUTE_SUBSCRIPTIONS_ADDITIONAL_FORM_DATA = "additional-form-data"; + private static final String DEFAULT_PLUGINS_HOST = "http://plugins.jetbrains.com"; ApplicationInfoImpl() { @@ -554,6 +569,37 @@ public class ApplicationInfoImpl extends ApplicationInfoEx { return myAboutLogoRect; } + @Override + public String getSubscriptionFormId() { + return mySubscriptionFormId; + } + + @Override + public String getSubscriptionNewsKey() { + return mySubscriptionNewsKey; + } + + @Override + public String getSubscriptionNewsValue() { + return mySubscriptionNewsValue; + } + + @Override + public String getSubscriptionTipsKey() { + return mySubscriptionTipsKey; + } + + @Override + public boolean areSubscriptionTipsAvailable() { + return mySubscriptionTipsAvailable; + } + + @Nullable + @Override + public String getSubscriptionAdditionalFormData() { + return mySubscriptionAdditionalFormData; + } + private static ApplicationInfoImpl ourShadowInstance; public boolean isBetaOrRC() { @@ -866,6 +912,15 @@ public class ApplicationInfoImpl extends ApplicationInfoEx { } } + Element subscriptionsElement = parentNode.getChild(ELEMENT_SUBSCRIPTIONS); + if (subscriptionsElement != null) { + mySubscriptionFormId = subscriptionsElement.getAttributeValue(ATTRIBUTE_SUBSCRIPTIONS_FORM_ID); + mySubscriptionNewsKey = subscriptionsElement.getAttributeValue(ATTRIBUTE_SUBSCRIPTIONS_NEWS_KEY); + mySubscriptionNewsValue = subscriptionsElement.getAttributeValue(ATTRIBUTE_SUBSCRIPTIONS_NEWS_VALUE, "yes"); + mySubscriptionTipsKey = subscriptionsElement.getAttributeValue(ATTRIBUTE_SUBSCRIPTIONS_TIPS_KEY); + mySubscriptionTipsAvailable = Boolean.parseBoolean(subscriptionsElement.getAttributeValue(ATTRIBUTE_SUBSCRIPTIONS_TIPS_AVAILABLE)); + mySubscriptionAdditionalFormData = subscriptionsElement.getAttributeValue(ATTRIBUTE_SUBSCRIPTIONS_ADDITIONAL_FORM_DATA); + } } private static void setBuildNumber(String apiVersion, String buildNumber) { From 7621f6ae530195b02bc14ea555fa82ba21c5bec9 Mon Sep 17 00:00:00 2001 From: Yaroslav Lepenkin Date: Mon, 4 Jul 2016 15:51:27 +0300 Subject: [PATCH 44/50] [Recent Tests] show only failed tests and passed configurations in popup. On right arrow failed test suite and configuration is shown --- .../testIntegration/RecentTestRunner.java | 27 ++- .../testIntegration/RecentTestsData.kt | 158 +++++++++++------- .../RecentTestsListProvider.java | 6 +- .../testIntegration/RunConfigurationEntry.kt | 134 ++++++++------- .../testIntegration/SelectTestStep.kt | 122 ++++++++++++-- .../testIntegration/ShowRecentTests.java | 9 +- .../testIntergration/RecentTestsOrderTest.kt | 52 ++---- .../testIntergration/RecentTestsTest.kt | 31 +--- 8 files changed, 328 insertions(+), 211 deletions(-) diff --git a/java/execution/impl/src/com/intellij/testIntegration/RecentTestRunner.java b/java/execution/impl/src/com/intellij/testIntegration/RecentTestRunner.java index d17513b46541..155ec44f6cad 100644 --- a/java/execution/impl/src/com/intellij/testIntegration/RecentTestRunner.java +++ b/java/execution/impl/src/com/intellij/testIntegration/RecentTestRunner.java @@ -37,8 +37,8 @@ public interface RecentTestRunner { } void setMode(Mode mode); - void run(String url); - void run(RunnerAndConfigurationSettings configuration); + + void run(RecentTestsPopupEntry entry); } class RecentTestRunnerImpl implements RecentTestRunner { @@ -67,14 +67,33 @@ class RecentTestRunnerImpl implements RecentTestRunner { } @Override - public void run(RunnerAndConfigurationSettings configuration) { + public void run(RecentTestsPopupEntry entry) { + entry.accept(new TestEntryVisitor() { + @Override + public void visitTest(@NotNull SingleTestEntry test) { + run(test.getUrl()); + } + + @Override + public void visitSuite(@NotNull SuiteEntry suite) { + run(suite.getSuiteUrl()); + } + + @Override + public void visitRunConfiguration(@NotNull RunConfigurationEntry configuration) { + run(configuration.getRunSettings()); + } + }); + } + + private void run(RunnerAndConfigurationSettings configuration) { Executor executor = myCurrentAction == RUN ? DefaultRunExecutor.getRunExecutorInstance() : DefaultDebugExecutor.getDebugExecutorInstance(); ProgramRunnerUtil.executeConfiguration(myProject, configuration, executor); } - public void run(@NotNull String url) { + private void run(@NotNull String url) { Location location = myTestLocator.getLocation(url); if (location == null) { return; diff --git a/java/execution/impl/src/com/intellij/testIntegration/RecentTestsData.kt b/java/execution/impl/src/com/intellij/testIntegration/RecentTestsData.kt index e0072f33a281..c67fd2172953 100644 --- a/java/execution/impl/src/com/intellij/testIntegration/RecentTestsData.kt +++ b/java/execution/impl/src/com/intellij/testIntegration/RecentTestsData.kt @@ -25,68 +25,61 @@ fun SuiteEntry.isMyTest(test: SingleTestEntry): Boolean { return testName.startsWith(this.suiteName) } +data class SingleTestInfo(val test: SingleTestEntry, val runConfigurationName: String) + class RecentTestsData { private val runConfigurationSuites = hashMapOf() - - private var unmatchedRunConfigurationTests = arrayListOf() - - private val urlSuites = mutableListOf() - private var unmatchedUrlTests = mutableListOf() - + private var testsWithoutSuites = arrayListOf() - fun addSuite(url: String, magnitude: Magnitude, runDate: Date, runConfiguration: RunnerAndConfigurationSettings?) { - val suite = SuiteEntry(url, magnitude, runDate) - if (runConfiguration != null) { - addRunConfigurationSuite(suite, runConfiguration) - } - else { - addUrlSuite(suite) - } + fun addSuite(url: String, runDate: Date, runConfiguration: RunnerAndConfigurationSettings) { + val suite = SuiteEntry(url, runDate) + addRunConfigurationSuite(suite, runConfiguration) } - fun addTest(url: String, magnitude: Magnitude, runDate: Date, runConfiguration: RunnerAndConfigurationSettings?) { - val test = SingleTestEntry(url, magnitude, runDate) - if (runConfiguration != null) { - addRunConfigurationTest(test, runConfiguration) - } - else { - addUrlTest(test) - } + fun addTest(url: String, magnitude: Magnitude, runDate: Date, runConfiguration: RunnerAndConfigurationSettings) { + val test = SingleTestEntry(url, runDate, magnitude) + addRunConfigurationTest(test, runConfiguration) } - private fun addUrlSuite(suite: SuiteEntry) { - val suiteTests = unmatchedUrlTests.filter { suite.isMyTest(it) } - suiteTests.forEach { suite.addTest(it) } - - unmatchedUrlTests = unmatchedUrlTests.filterTo(arrayListOf(), { !suite.isMyTest(it) }) - - urlSuites.add(suite) - } - private fun addRunConfigurationSuite(suite: SuiteEntry, config: RunnerAndConfigurationSettings) { - val suiteTests = unmatchedRunConfigurationTests.filter { suite.isMyTest(it) } - suiteTests.forEach { suite.addTest(it) } + moveSuiteTestsToSuite(suite, config) - unmatchedRunConfigurationTests = unmatchedRunConfigurationTests.filterTo(arrayListOf(), { !suite.isMyTest(it) }) - val id = config.uniqueID - runConfigurationSuites[id]?.addSuite(suite) ?: runConfigurationSuites.put(id, RunConfigurationEntry(config, suite)) + val entry = runConfigurationSuites[id] + if (entry != null) { + entry.addSuite(suite) + } + else { + runConfigurationSuites.put(id, RunConfigurationEntry(config, suite)) + } } - private fun addUrlTest(test: SingleTestEntry) { - findUrlSuite(test.url)?.addTest(test) ?: unmatchedUrlTests.add(test) + private fun moveSuiteTestsToSuite(suite: SuiteEntry, config: RunnerAndConfigurationSettings) { + val filteredTests = arrayListOf() + + testsWithoutSuites.forEach { + if (suite.isMyTest(it.test) && config.name == it.runConfigurationName) { + suite.addTest(it.test) + } + else { + filteredTests.add(it) + } + } + + testsWithoutSuites = filteredTests } private fun addRunConfigurationTest(test: SingleTestEntry, runConfiguration: RunnerAndConfigurationSettings) { - findRunConfigurationSuite(test.url, runConfiguration)?.addTest(test) ?: unmatchedRunConfigurationTests.add(test) + val suiteEntry = findRunConfigurationSuite(test.url, runConfiguration) + if (suiteEntry != null) { + suiteEntry.addTest(test) + } + else { + testsWithoutSuites.add(SingleTestInfo(test, runConfiguration.name)) + } } - - private fun findUrlSuite(url: String) = urlSuites.find { - val testName = VirtualFileManager.extractPath(url) - testName.startsWith(it.suiteName) - } - + private fun findRunConfigurationSuite(url: String, runConfiguration: RunnerAndConfigurationSettings): SuiteEntry? { val pack: RunConfigurationEntry = runConfigurationSuites[runConfiguration.uniqueID] ?: return null val testName = VirtualFileManager.extractPath(url) @@ -99,28 +92,69 @@ class RecentTestsData { return null } - - fun computeConfigurationSuites() = runConfigurationSuites.values - .fold(arrayListOf(), { total: List, entry: RunConfigurationEntry -> total + entry.suites }) fun getTestsToShow(): List { - val allConfigurationSuites = computeConfigurationSuites() - - unmatchedRunConfigurationTests.forEach { - val currentTest = it - allConfigurationSuites.find { it.isMyTest(currentTest) }?.addTest(currentTest) + val allConfigurations = runConfigurationSuites.values + + val allSuites = allConfigurations.fold(arrayListOf(), { list: List, entry -> list + entry.suites }) + testsWithoutSuites.forEach { + val info = it + allSuites.find { it.isMyTest(info.test) }?.let { info.test.suite = it } } - unmatchedUrlTests.forEach { - val currentTest = it - urlSuites.find { it.isMyTest(currentTest) }?.addTest(currentTest) - } + val testsCollector = SingleTestCollector() + allConfigurations.forEach { it.accept(testsCollector) } + val failedTests = testsCollector.tests.filter { it.failed } - return (runConfigurationSuites.values + urlSuites) - .sortedByDescending { it.runDate } - .fold(listOf(), { popupList, currentEntry -> - popupList + currentEntry.getEntriesToShow() - }) + val configsCollector = ConfigurationsCollector() + allConfigurations.forEach { it.accept(configsCollector) } + val passedConfigurations = configsCollector.entries.filter { !it.failed } + + val entriesToShow = failedTests + passedConfigurations + testsWithoutSuites.map { it.test }.filter { it.suite != null && it.failed } + + return entriesToShow.sortedByDescending { it.runDate } } +} + +class UrlsCollector: TestEntryVisitor() { + val urls = mutableListOf() + + override fun visitSuite(suite: SuiteEntry) { + urls.add(suite.suiteUrl) + suite.tests.forEach { urls.add(it.url) } + } + + override fun visitRunConfiguration(configuration: RunConfigurationEntry) { + configuration.suites.forEach { visitSuite(it) } + } +} + + +class SingleTestCollector : TestEntryVisitor() { + val tests = mutableListOf() + override fun visitTest(test: SingleTestEntry) { + tests.add(test) + } + + override fun visitSuite(suite: SuiteEntry) { + suite.tests.forEach { it.accept(this) } + } + + override fun visitRunConfiguration(configuration: RunConfigurationEntry) { + configuration.suites.forEach { it.accept(this) } + } +} + + +class ConfigurationsCollector : TestEntryVisitor() { + val entries = mutableListOf() + + override fun visitRunConfiguration(configuration: RunConfigurationEntry) { + entries.add(configuration) + } + + override fun visitSuite(suite: SuiteEntry) { + entries.add(suite) + } } \ No newline at end of file diff --git a/java/execution/impl/src/com/intellij/testIntegration/RecentTestsListProvider.java b/java/execution/impl/src/com/intellij/testIntegration/RecentTestsListProvider.java index 66ff8617809e..25a83e32f785 100644 --- a/java/execution/impl/src/com/intellij/testIntegration/RecentTestsListProvider.java +++ b/java/execution/impl/src/com/intellij/testIntegration/RecentTestsListProvider.java @@ -98,8 +98,12 @@ public class RecentTestsListProvider { } RunnerAndConfigurationSettings runConfiguration = myConfigurationProvider.getConfiguration(record); + if (runConfiguration == null) { + return; + } + if (TestLocator.isSuite(url)) { - data.addSuite(url, magnitude, record.date, runConfiguration); + data.addSuite(url, record.date, runConfiguration); } else { data.addTest(url, magnitude, record.date, runConfiguration); diff --git a/java/execution/impl/src/com/intellij/testIntegration/RunConfigurationEntry.kt b/java/execution/impl/src/com/intellij/testIntegration/RunConfigurationEntry.kt index a0263b085be6..daea4350491c 100644 --- a/java/execution/impl/src/com/intellij/testIntegration/RunConfigurationEntry.kt +++ b/java/execution/impl/src/com/intellij/testIntegration/RunConfigurationEntry.kt @@ -16,72 +16,76 @@ package com.intellij.testIntegration import com.intellij.execution.RunnerAndConfigurationSettings +import com.intellij.execution.testframework.TestIconMapper import com.intellij.execution.testframework.sm.runner.states.TestStateInfo -import com.intellij.execution.testframework.sm.runner.states.TestStateInfo.Magnitude.* +import com.intellij.execution.testframework.sm.runner.states.TestStateInfo.Magnitude.ERROR_INDEX +import com.intellij.execution.testframework.sm.runner.states.TestStateInfo.Magnitude.FAILED_INDEX +import com.intellij.icons.AllIcons import com.intellij.openapi.vfs.VirtualFileManager -import com.intellij.psi.PsiElement import java.util.* +import javax.swing.Icon + interface RecentTestsPopupEntry { - val runDate: Date - val magnitude: TestStateInfo.Magnitude + val icon: Icon? val presentation: String - - val testsUrls: List - - fun run(runner: RecentTestRunner) - - open fun navigatableElement(locator: TestLocator): PsiElement? = null + val runDate: Date - fun getEntriesToShow(): List + val failed: Boolean + + fun accept(visitor: TestEntryVisitor) } -open class SingleTestEntry(val url: String, - override val magnitude: TestStateInfo.Magnitude, - override val runDate: Date) : RecentTestsPopupEntry + +abstract class TestEntryVisitor { + open fun visitTest(test: SingleTestEntry) = Unit + open fun visitSuite(suite: SuiteEntry) = Unit + open fun visitRunConfiguration(configuration: RunConfigurationEntry) = Unit +} + +class SingleTestEntry(val url: String, + override val runDate: Date, + private val magnitude: TestStateInfo.Magnitude) : RecentTestsPopupEntry { override val presentation = VirtualFileManager.extractPath(url) - override val testsUrls = listOf(url) - - override fun run(runner: RecentTestRunner) { - runner.run(url) + override val icon = TestIconMapper.getIcon(magnitude) + + override val failed = magnitude == ERROR_INDEX || magnitude == FAILED_INDEX + + var suite: SuiteEntry? = null + + override fun accept(visitor: TestEntryVisitor) { + visitor.visitTest(this) } - - override fun navigatableElement(locator: TestLocator) = locator.getLocation(url)?.psiElement - - override fun getEntriesToShow(): List = listOf(this) } -class SuiteEntry(url: String, magnitude: TestStateInfo.Magnitude, runDate: Date) : SingleTestEntry(url, magnitude, runDate) { - - private val tests = hashSetOf() - override val testsUrls: List - get() = tests.fold(listOf(), { acc, testEntry -> acc + testEntry.testsUrls }) - - val suiteName = VirtualFileManager.extractPath(url) - - val failedTests: List - get() = tests.filter { it.magnitude == FAILED_INDEX || it.magnitude == ERROR_INDEX } - - fun addTest(info: SingleTestEntry) = tests.add(info) +class SuiteEntry(val suiteUrl: String, override val runDate: Date) : RecentTestsPopupEntry { - override val presentation = suiteName - - override fun getEntriesToShow(): List { - val failed = failedTests - if (failed.size > 0) { - return failed.sortedByDescending { it.runDate } + this + val tests = hashSetOf() + val suiteName = VirtualFileManager.extractPath(suiteUrl) + + var runConfiguration: RunConfigurationEntry? = null + + override val presentation = VirtualFileManager.extractPath(suiteUrl) + override val icon = AllIcons.RunConfigurations.Junit + + override val failed: Boolean + get() { + return tests.find { it.failed } != null } - return listOf(this) - } - override val magnitude: TestStateInfo.Magnitude by lazy { - tests.find { it.magnitude != PASSED_INDEX && it.magnitude != COMPLETE_INDEX }?.magnitude ?: PASSED_INDEX + fun addTest(test: SingleTestEntry) { + tests.add(test) + test.suite = this } - + + override fun accept(visitor: TestEntryVisitor) { + visitor.visitSuite(this) + } + } @@ -93,34 +97,28 @@ class RunConfigurationEntry(val runSettings: RunnerAndConfigurationSettings, ini addSuite(initial) } - fun addSuite(s: SuiteEntry) = suites.add(s) + override val runDate: Date + get() { + return suites.minBy { it.runDate }!!.runDate + } + + + override val failed: Boolean + get() { + return suites.find { it.failed } != null + } - override val runDate = suites.map { it.runDate }.min()!! - - override val magnitude: TestStateInfo.Magnitude by lazy { - suites.find { it.magnitude != PASSED_INDEX && it.magnitude != COMPLETE_INDEX }?.magnitude ?: PASSED_INDEX + fun addSuite(suite: SuiteEntry) { + suites.add(suite) + suite.runConfiguration = this } override val presentation = runSettings.name - override val testsUrls: List - get() = suites.fold(listOf(), { list, suite -> list + suite.testsUrls }) - - override fun run(runner: RecentTestRunner) { - runner.run(runSettings) - } + override val icon = AllIcons.RunConfigurations.Junit - override fun getEntriesToShow(): List { - if (suites.size == 1) { - return suites[0].getEntriesToShow() - } - - return suites - .filter { it.failedTests.size > 0} - .sortedByDescending { it.runDate } - .fold(listOf(), { popupList, currentEntry -> - popupList + currentEntry.getEntriesToShow() - }) + this + override fun accept(visitor: TestEntryVisitor) { + visitor.visitRunConfiguration(this) } -} +} \ No newline at end of file diff --git a/java/execution/impl/src/com/intellij/testIntegration/SelectTestStep.kt b/java/execution/impl/src/com/intellij/testIntegration/SelectTestStep.kt index 73e58109d227..d2a5b85a67ff 100644 --- a/java/execution/impl/src/com/intellij/testIntegration/SelectTestStep.kt +++ b/java/execution/impl/src/com/intellij/testIntegration/SelectTestStep.kt @@ -15,12 +15,13 @@ */ package com.intellij.testIntegration -import com.intellij.execution.testframework.TestIconMapper +import com.intellij.icons.AllIcons import com.intellij.openapi.keymap.MacKeymapUtil import com.intellij.openapi.ui.popup.ListPopupStep import com.intellij.openapi.ui.popup.PopupStep import com.intellij.openapi.ui.popup.util.BaseListPopupStep import com.intellij.openapi.util.SystemInfo +import com.intellij.psi.PsiElement import com.intellij.ui.popup.list.ListPopupImpl import com.intellij.util.PsiNavigateUtil import java.awt.event.ActionEvent @@ -31,9 +32,7 @@ import javax.swing.KeyStroke class RecentTestsListPopup(popupStep: ListPopupStep, private val testRunner: RecentTestRunner, - private val locator: TestLocator) - : ListPopupImpl(popupStep) -{ + private val locator: TestLocator) : ListPopupImpl(popupStep) { init { shiftReleased() @@ -58,16 +57,36 @@ class RecentTestsListPopup(popupStep: ListPopupStep, override fun actionPerformed(e: ActionEvent) { val values = selectedValues if (values.size == 1) { - val element = (values[0] as RecentTestsPopupEntry).navigatableElement(locator) - if (element != null) { + val entry = values[0] as RecentTestsPopupEntry + getElement(entry)?.let { cancel() - PsiNavigateUtil.navigate(element) + PsiNavigateUtil.navigate(it) } } } }) } + private fun getElement(entry: RecentTestsPopupEntry): PsiElement? { + var element: PsiElement? = null + entry.accept(object : TestEntryVisitor() { + override fun visitTest(test: SingleTestEntry) { + element = locator.getLocation(test.url)?.psiElement + } + + override fun visitSuite(suite: SuiteEntry) { + element = locator.getLocation(suite.suiteUrl)?.psiElement + } + + override fun visitRunConfiguration(configuration: RunConfigurationEntry) { + if (configuration.suites.size == 1) { + visitSuite(configuration.suites[0]) + } + } + }) + return element + } + private fun shiftPressed() { setCaption("Debug Recent Tests") testRunner.setMode(RecentTestRunner.Mode.DEBUG) @@ -80,22 +99,99 @@ class RecentTestsListPopup(popupStep: ListPopupStep, } -class SelectTestStep(tests: List, - private val runner: RecentTestRunner) - : BaseListPopupStep("Debug Recent Tests", tests) +class SelectTestStep(title: String?, + tests: List, + private val runner: RecentTestRunner) : BaseListPopupStep(title, tests) { override fun getIconFor(value: RecentTestsPopupEntry): Icon? { - return TestIconMapper.getIcon(value.magnitude) + if (value is SingleTestEntry) { + return AllIcons.RunConfigurations.TestFailed + } + else { + return AllIcons.RunConfigurations.TestPassed + } } override fun getTextFor(value: RecentTestsPopupEntry) = value.presentation override fun isSpeedSearchEnabled() = true + override fun hasSubstep(selectedValue: RecentTestsPopupEntry) = getConfigurations(selectedValue).isNotEmpty() + override fun onChosen(entry: RecentTestsPopupEntry, finalChoice: Boolean): PopupStep? { - entry.run(runner) - return null + if (finalChoice) { + runner.run(entry) + return null + } + + val configurations = getConfigurations(entry) + return SelectConfigurationStep(configurations, runner) + } + + private fun getConfigurations(entry: RecentTestsPopupEntry): List { + val items = mutableListOf() + + entry.accept(object : TestEntryVisitor() { + override fun visitTest(test: SingleTestEntry) { + val suite = test.suite ?: return + val configuration = suite.runConfiguration + if (configuration == null) { + items.add(suite) + return + } + + if (isSingleTestConfiguration(configuration)) { + items.add(suite) + return + } + + items.add(configuration) + if (configuration.suites.size > 1) { + items.add(0, suite) + } + } + + private fun isSingleTestConfiguration(configuration: RunConfigurationEntry): Boolean { + val suites = configuration.suites + return suites.size == 1 && suites[0].tests.size == 1 + } + + }) + + return items } } + + +class SelectConfigurationStep(private val items: List, + private val runner: RecentTestRunner) + : BaseListPopupStep(null, items) +{ + + override fun getTextFor(value: RecentTestsPopupEntry): String { + var presentation = value.presentation + value.accept(object : TestEntryVisitor() { + override fun visitSuite(suite: SuiteEntry) { + presentation = "[suite] " + presentation + } + + override fun visitRunConfiguration(configuration: RunConfigurationEntry) { + presentation = "[configuration] " + presentation + } + }) + return presentation + } + + override fun getIconFor(value: RecentTestsPopupEntry?) = AllIcons.RunConfigurations.Junit + + override fun onChosen(selectedValue: RecentTestsPopupEntry, finalChoice: Boolean): PopupStep? { + if (finalChoice) { + runner.run(selectedValue) + } + + return null + } + +} \ No newline at end of file diff --git a/java/execution/impl/src/com/intellij/testIntegration/ShowRecentTests.java b/java/execution/impl/src/com/intellij/testIntegration/ShowRecentTests.java index 2807216931c7..81ceea8be303 100644 --- a/java/execution/impl/src/com/intellij/testIntegration/ShowRecentTests.java +++ b/java/execution/impl/src/com/intellij/testIntegration/ShowRecentTests.java @@ -22,7 +22,6 @@ import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; import com.intellij.util.Time; -import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import java.util.Date; @@ -60,7 +59,7 @@ public class ShowRecentTests extends AnAction { List entries = listProvider.getTestsToShow(); - SelectTestStep selectStepTest = new SelectTestStep(entries, testRunner); + SelectTestStep selectStepTest = new SelectTestStep("Debug Recent Tests", entries, testRunner); RecentTestsListPopup popup = new RecentTestsListPopup(selectStepTest, testRunner, testLocator); popup.showCenteredInCurrentWindow(project); @@ -69,9 +68,9 @@ public class ShowRecentTests extends AnAction { } private static void cleanDeadTests(List entries, TestLocator testLocator, TestStateStorage testStorage) { - List urls = ContainerUtil.newArrayList(); - entries.forEach((entry) -> urls.addAll(entry.getTestsUrls())); - ApplicationManager.getApplication().executeOnPooledThread(new DeadTestsCleaner(testStorage, urls, testLocator)); + UrlsCollector collector = new UrlsCollector(); + entries.forEach((e) -> e.accept(collector)); + ApplicationManager.getApplication().executeOnPooledThread(new DeadTestsCleaner(testStorage, collector.getUrls(), testLocator)); } } diff --git a/java/java-tests/testSrc/com/intellij/testIntergration/RecentTestsOrderTest.kt b/java/java-tests/testSrc/com/intellij/testIntergration/RecentTestsOrderTest.kt index b30883240cf0..364b10ed3595 100644 --- a/java/java-tests/testSrc/com/intellij/testIntergration/RecentTestsOrderTest.kt +++ b/java/java-tests/testSrc/com/intellij/testIntergration/RecentTestsOrderTest.kt @@ -37,11 +37,11 @@ class RecentTestsOrderTest: LightIdeaTestCase() { } fun addPassedSuite(suiteUrl: String, date: Date = Date(), runConfiguration: RunnerAndConfigurationSettings = allTests) { - data.addSuite(suiteUrl, PASSED_INDEX, date, runConfiguration) + data.addSuite(suiteUrl, date, runConfiguration) } fun addFailedSuite(suiteUrl: String, date: Date = Date(), runConfiguration: RunnerAndConfigurationSettings = allTests) { - data.addSuite(suiteUrl, FAILED_INDEX, date, runConfiguration) + data.addSuite(suiteUrl, date, runConfiguration) } fun addPassedTest(testUrl: String, date: Date = Date(), runConfiguration: RunnerAndConfigurationSettings = allTests) { @@ -57,11 +57,11 @@ class RecentTestsOrderTest: LightIdeaTestCase() { val test1 = "MySingleTest.test1".test() data.addTest(test1, PASSED_INDEX, now, allTests) - data.addSuite(suite, PASSED_INDEX, now, allTests) + data.addSuite(suite, now, allTests) val testsToShow = data.getTestsToShow() assertThat(testsToShow).hasSize(1) - assertThat(testsToShow[0].presentation).isEqualTo("MySingleTest") + assertThat(testsToShow[0].presentation).isEqualTo("all tests") } fun `test run configuration with multiple suites shows run configuration name`() { @@ -90,13 +90,10 @@ class RecentTestsOrderTest: LightIdeaTestCase() { addFailedTest(test) val tests = data.getTestsToShow() - assertThat(tests).hasSize(2) + assertThat(tests).hasSize(1) assertThat(tests[0].presentation).isEqualTo("SingleTest.test") - assertThat(tests[0].magnitude).isEqualTo(FAILED_INDEX) - - assertThat(tests[1].presentation).isEqualTo("SingleTest") - assertThat(tests[1].magnitude).isEqualTo(FAILED_INDEX) + assertThat(tests[0].failed).isEqualTo(true) } fun `test show failed suite and test in run configuration`() { @@ -111,41 +108,29 @@ class RecentTestsOrderTest: LightIdeaTestCase() { addPassedSuite("PassedSuite".suite()) val tests = data.getTestsToShow() - assertThat(tests).hasSize(3) + assertThat(tests).hasSize(1) assertThat(tests[0].presentation).isEqualTo("SingleTest.test") - assertThat(tests[0].magnitude).isEqualTo(FAILED_INDEX) - - assertThat(tests[1].presentation).isEqualTo("SingleTest") - assertThat(tests[1].magnitude).isEqualTo(FAILED_INDEX) - - assertThat(tests[2].presentation).isEqualTo("all tests") - assertThat(tests[2].magnitude).isEqualTo(FAILED_INDEX) + assertThat(tests[0].failed).isEqualTo(true) } fun `test single test run doesn't override suite status`() { val singleTestConfig = mockConfiguration("single test", "Junit.single test") val newNow = Date(now.time + 100000) - //current single test run - addFailedSuite("Test".suite(), newNow, singleTestConfig) - addFailedTest("Test.testOK".test(), newNow, singleTestConfig) //previous all suite run - addPassedTest("Test.testOK".test(), now, allTests) addFailedTest("Test.testFailed".test(), now, allTests) + //current single test run + addPassedSuite("Test".suite(), newNow, singleTestConfig) + addPassedTest("Test.testOK".test(), newNow, singleTestConfig) + val tests = data.getTestsToShow() - assertThat(tests).hasSize(3) - - assertThat(tests[0].presentation).isEqualTo("Test.testOK") - assertThat(tests[0].magnitude).isEqualTo(FAILED_INDEX) + assertThat(tests).hasSize(2) + assertThat(tests[0].presentation).isEqualTo("single test") assertThat(tests[1].presentation).isEqualTo("Test.testFailed") - assertThat(tests[1].magnitude).isEqualTo(FAILED_INDEX) - - assertThat(tests[2].presentation).isEqualTo("Test") - assertThat(tests[2].magnitude).isEqualTo(FAILED_INDEX) } @@ -156,18 +141,15 @@ class RecentTestsOrderTest: LightIdeaTestCase() { //previous all suite run addPassedTest("Test.testOK".test(), now, allTests) - addFailedTest("Test.testFailed".test(), now, allTests) //current single test run addFailedSuite("Test".suite(), newNow, singleTestConfig) - addFailedTest("Test.testOK".test(), newNow, singleTestConfig) + addFailedTest("Test.testFailed".test(), newNow, singleTestConfig) val tests = data.getTestsToShow() - assertThat(tests).hasSize(3) + assertThat(tests).hasSize(1) - assertThat(tests[0].presentation).isEqualTo("Test.testOK") - assertThat(tests[1].presentation).isEqualTo("Test.testFailed") - assertThat(tests[2].presentation).isEqualTo("Test") + assertThat(tests[0].presentation).isEqualTo("Test.testFailed") } } \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/testIntergration/RecentTestsTest.kt b/java/java-tests/testSrc/com/intellij/testIntergration/RecentTestsTest.kt index 13967b0baa78..87dd94da7420 100644 --- a/java/java-tests/testSrc/com/intellij/testIntergration/RecentTestsTest.kt +++ b/java/java-tests/testSrc/com/intellij/testIntergration/RecentTestsTest.kt @@ -48,18 +48,10 @@ class RecentTestsStepTest: LightIdeaTestCase() { now = Date() } - fun `test show suites without run configuration`() { - data.addTest("Test.x".test(), PASSED_INDEX, now, null) - data.addSuite("Test".suite(), PASSED_INDEX, now, null) - - val tests = data.getTestsToShow() - assertThat(tests).hasSize(1) - } - fun `test all tests passed`() { data.addTest("Test.textXXX".test(), PASSED_INDEX, now, allTests) - data.addSuite("Test".suite(), PASSED_INDEX, now, allTests) - data.addSuite("JFSDTest".suite(), PASSED_INDEX, now, allTests) + data.addSuite("Test".suite(), now, allTests) + data.addSuite("JFSDTest".suite(), now, allTests) data.addTest("Test.textYYY".test(), PASSED_INDEX, now, allTests) data.addTest("JFSDTest.testItMakesMeSadToFixIt".test(), PASSED_INDEX, now, allTests) data.addTest("Test.textZZZ".test(), PASSED_INDEX, now, allTests) @@ -73,8 +65,8 @@ class RecentTestsStepTest: LightIdeaTestCase() { fun `test if one failed in run configuration show failed suite`() { - data.addSuite("JFSDTest".suite(), FAILED_INDEX, now, allTests) - data.addSuite("Test".test(), PASSED_INDEX, now, allTests) + data.addSuite("JFSDTest".suite(), now, allTests) + data.addSuite("Test".suite(), now, allTests) data.addTest("JFSDTest.testItMakesMeSadToFixIt".test(), FAILED_INDEX, now, allTests) data.addTest("JFSDTest.testUnconditionalAlignmentErrorneous".test(), PASSED_INDEX, now, allTests) @@ -83,28 +75,21 @@ class RecentTestsStepTest: LightIdeaTestCase() { val tests = data.getTestsToShow() - assertThat(tests).hasSize(3) + assertThat(tests).hasSize(1) assertThat(tests[0].presentation).isEqualTo("JFSDTest.testItMakesMeSadToFixIt") - assertThat(tests[0].magnitude).isEqualTo(FAILED_INDEX) - - assertThat(tests[1].presentation).isEqualTo("JFSDTest") - assertThat(tests[1].magnitude).isEqualTo(FAILED_INDEX) - - assertThat(tests[2].presentation).isEqualTo("all tests") - assertThat(tests[2].magnitude).isEqualTo(FAILED_INDEX) + assertThat(tests[0].failed).isEqualTo(true) } fun `test if configuration with single test show failed test`() { - data.addSuite("JFSDTest".suite(), FAILED_INDEX, now, allTests) + data.addSuite("JFSDTest".suite(), now, allTests) data.addTest("JFSDTest.testItMakesMeSadToFixIt".test(), FAILED_INDEX, now, allTests) data.addTest("JFSDTest.testUnconditionalAlignmentErrorneous".test(), PASSED_INDEX, now, allTests) val tests = data.getTestsToShow() - assertThat(tests).hasSize(2) + assertThat(tests).hasSize(1) assertThat(tests[0].presentation).isEqualTo("JFSDTest.testItMakesMeSadToFixIt") - assertThat(tests[1].presentation).isEqualTo("JFSDTest") } From aa0f1add772a1a36a4c7fa7cbe0ffa09243d6d1f Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Mon, 4 Jul 2016 18:58:53 +0300 Subject: [PATCH 45/50] IDEA-157667 Editor's scrollbar thumb: alpha and colors fix border drawing by filling a corresponding path it is slightly slower but it is more accurate --- .../src/com/intellij/ui/components/JBScrollPane.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) 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 34fa55ca3efc..2cf04c24af5b 100644 --- a/platform/platform-api/src/com/intellij/ui/components/JBScrollPane.java +++ b/platform/platform-api/src/com/intellij/ui/components/JBScrollPane.java @@ -44,6 +44,7 @@ import java.awt.event.InputEvent; import java.awt.event.MouseEvent; import java.awt.event.MouseWheelEvent; import java.awt.event.MouseWheelListener; +import java.awt.geom.Path2D; import java.awt.geom.RoundRectangle2D; import java.awt.image.*; import java.lang.reflect.Field; @@ -937,13 +938,11 @@ public class JBScrollPane extends JScrollPane { g.fillRoundRect(x, y, width, height, arc, arc); } if (myDrawColor != null) { + Path2D path = new Path2D.Double(Path2D.WIND_EVEN_ODD); + path.append(new RoundRectangle2D.Double(x, y, width, height, arc, arc), false); + path.append(new RoundRectangle2D.Double(x + 1, y + 1, width - 2, height - 2, arc - 2, arc - 2), false); g.setColor(myDrawColor); - if (UIUtil.isRetina(g)) { - g.drawRoundRect(x, y, width, height, arc, arc); - } - else { - g.drawRoundRect(x, y, width - 1, height - 1, arc, arc); - } + g.fill(path); } g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, old); } From a769a1ba60f5a3a6a8d634c4ea6122737b21accd Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Mon, 4 Jul 2016 20:30:56 +0300 Subject: [PATCH 46/50] IDEA-157555 Modal dialogs are shown twice support opening of several files --- .../ide/MacOSApplicationProvider.java | 96 +++++++++++-------- 1 file changed, 57 insertions(+), 39 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/ide/MacOSApplicationProvider.java b/platform/platform-impl/src/com/intellij/ide/MacOSApplicationProvider.java index 44b8711158d0..2f6962a46e84 100644 --- a/platform/platform-impl/src/com/intellij/ide/MacOSApplicationProvider.java +++ b/platform/platform-impl/src/com/intellij/ide/MacOSApplicationProvider.java @@ -122,32 +122,34 @@ public class MacOSApplicationProvider implements ApplicationComponent { private static class Worker { public static void initMacApplication() { Application application = Application.getApplication(); - application.setAboutHandler(event -> AboutAction.perform(getProject())); + application.setAboutHandler(event -> AboutAction.perform(getProject(false))); application.setPreferencesHandler(event -> { - Project project = getNotNullProject(); - submit(() -> ShowSettingsAction.perform(project)); + Project project = getProject(true); + submit("Preferences", () -> ShowSettingsAction.perform(project)); }); application.setQuitHandler((event, response) -> { - submit(ExitAction::perform); + submit("Quit", ExitAction::perform); response.cancelQuit(); }); application.setOpenFileHandler(event -> { - Project project = getProject(); + Project project = getProject(false); List list = event.getFiles(); - LOG.debug("MacMenu: files found ", list.size()); if (list.isEmpty()) return; - File file = list.get(0); - submit(() -> { - LOG.debug("MacMenu: try to open file"); - if (ProjectUtil.openOrImport(file.getAbsolutePath(), project, true) != null) { - LOG.debug("MacMenu: load project for ", file); - IdeaApplication.getInstance().setPerformProjectLoad(false); - return; + submit("OpenFile", () -> { + for (File file : list) { + if (ProjectUtil.openOrImport(file.getAbsolutePath(), project, true) != null) { + LOG.debug("MacMenu: load project from ", file); + IdeaApplication.getInstance().setPerformProjectLoad(false); + return; + } } - LOG.debug("MacMenu: project = ", project); - if (project != null && file.exists()) { - LOG.debug("MacMenu: open file ", file); - OpenFileAction.openFile(file.getAbsolutePath(), project); + if (project != null) { + for (File file : list) { + if (file.exists()) { + LOG.debug("MacMenu: open file ", file); + OpenFileAction.openFile(file.getAbsolutePath(), project); + } + } } }); }); @@ -179,33 +181,49 @@ public class MacOSApplicationProvider implements ApplicationComponent { Foundation.invoke(pool, Foundation.createSelector("release")); } - @SuppressWarnings("deprecation") - private static Project getProject() { - return CommonDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext()); + private static Project getProject(boolean useDefault) { + @SuppressWarnings("deprecation") + Project project = CommonDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext()); + if (project == null) { + LOG.debug("MacMenu: no project in data context"); + Project[] projects = ProjectManager.getInstance().getOpenProjects(); + project = projects.length > 0 ? projects[0] : null; + if (project == null && useDefault) { + LOG.debug("MacMenu: use default project instead"); + project = ProjectManager.getInstance().getDefaultProject(); + } + } + LOG.debug("MacMenu: project = ", project); + return project; } - @NotNull - private static Project getNotNullProject() { - Project project = getProject(); - return project != null ? project : ProjectManager.getInstance().getDefaultProject(); - } - - private static void submit(@NotNull Runnable task) { + private static void submit(@NotNull String name, @NotNull Runnable task) { LOG.debug("MacMenu: on EDT = ", SwingUtilities.isEventDispatchThread(), "; ENABLED = ", ENABLED.get()); - if (!ENABLED.get()) return; - - Component component = IdeFocusManager.getGlobalInstance().getFocusOwner(); - if (component == null || IdeKeyEventDispatcher.isModalContext(component)) return; - - ENABLED.set(false); - TransactionGuard.submitTransaction(ApplicationManager.getApplication(), () -> { - try { - task.run(); + if (!ENABLED.get()) { + LOG.debug("MacMenu: disabled"); + } + else { + Component component = IdeFocusManager.getGlobalInstance().getFocusOwner(); + if (component == null) { + LOG.debug("MacMenu: no focused component"); } - finally { - ENABLED.set(true); + else if (IdeKeyEventDispatcher.isModalContext(component)) { + LOG.debug("MacMenu: component in modal context"); } - }); + else { + ENABLED.set(false); + TransactionGuard.submitTransaction(ApplicationManager.getApplication(), () -> { + try { + LOG.debug("MacMenu: init ", name); + task.run(); + } + finally { + LOG.debug("MacMenu: done ", name); + ENABLED.set(true); + } + }); + } + } } } } From 02d553dde1d107afde9f5b1eb27c2a2a2aaa2526 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Mon, 4 Jul 2016 19:36:40 +0200 Subject: [PATCH 47/50] make IG test light --- .../bugs/covariantEquals/interf/expected.xml | 2 -- .../CovariantEquals.java} | 0 .../ig/bugs/CovariantEqualsInspectionTest.java | 16 ++++++++++------ 3 files changed, 10 insertions(+), 8 deletions(-) delete mode 100644 plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/covariantEquals/interf/expected.xml rename plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/{covariantEquals/interf/Interf.java => covariant_equals/CovariantEquals.java} (100%) diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/covariantEquals/interf/expected.xml b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/covariantEquals/interf/expected.xml deleted file mode 100644 index 4704d91e891d..000000000000 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/covariantEquals/interf/expected.xml +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/covariantEquals/interf/Interf.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/covariant_equals/CovariantEquals.java similarity index 100% rename from plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/covariantEquals/interf/Interf.java rename to plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/covariant_equals/CovariantEquals.java diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/CovariantEqualsInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/CovariantEqualsInspectionTest.java index 204c66836339..f751f970a240 100644 --- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/CovariantEqualsInspectionTest.java +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/CovariantEqualsInspectionTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,15 +15,19 @@ */ package com.siyeh.ig.bugs; -import com.siyeh.ig.IGInspectionTestCase; +import com.intellij.codeInspection.InspectionProfileEntry; +import com.siyeh.ig.LightInspectionTestCase; +import org.jetbrains.annotations.Nullable; -public class CovariantEqualsInspectionTest extends IGInspectionTestCase { +public class CovariantEqualsInspectionTest extends LightInspectionTestCase { - public void testInterf() throws Exception { + public void testCovariantEquals() { doTest(); } - private void doTest() throws Exception { - doTest("com/siyeh/igtest/bugs/covariantEquals/" + getTestName(true), new CovariantEqualsInspection()); + @Nullable + @Override + protected InspectionProfileEntry getInspection() { + return new CovariantEqualsInspection(); } } From 2d97a336b99fa43fd0daa7430f20292148f66200 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Mon, 4 Jul 2016 21:00:31 +0200 Subject: [PATCH 48/50] IG: don't warn on covariant equals() when there is a super method --- .../ig/bugs/CovariantEqualsInspection.java | 23 +++++---------- .../covariant_equals/CovariantEquals.java | 28 +++++++++++++++++++ 2 files changed, 35 insertions(+), 16 deletions(-) diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/CovariantEqualsInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/CovariantEqualsInspection.java index d80b0b341616..9310fee55930 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/CovariantEqualsInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/CovariantEqualsInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2007 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2016 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,10 +16,12 @@ package com.siyeh.ig.bugs; import com.intellij.psi.*; +import com.intellij.psi.search.searches.SuperMethodsSearch; import com.siyeh.HardcodedMethodConstants; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.psiutils.MethodUtils; import com.siyeh.ig.psiutils.TypeUtils; import org.jetbrains.annotations.NotNull; @@ -71,25 +73,14 @@ public class CovariantEqualsInspection extends BaseInspection { } final PsiMethod[] methods = aClass.getMethods(); for (PsiMethod method1 : methods) { - if (isNonVariantEquals(method1)) { + if (MethodUtils.isEquals(method1)) { return; } } + if (SuperMethodsSearch.search(method, null, true, false).findFirst() != null) { + return; + } registerMethodError(method); } - - private static boolean isNonVariantEquals(PsiMethod method) { - final String name = method.getName(); - if (!HardcodedMethodConstants.EQUALS.equals(name)) { - return false; - } - final PsiParameterList paramList = method.getParameterList(); - final PsiParameter[] parameters = paramList.getParameters(); - if (parameters.length != 1) { - return false; - } - final PsiType argType = parameters[0].getType(); - return TypeUtils.isJavaLangObject(argType); - } } } \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/covariant_equals/CovariantEquals.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/covariant_equals/CovariantEquals.java index bc7b5a1e40c0..53d950c98cbd 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/covariant_equals/CovariantEquals.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/covariant_equals/CovariantEquals.java @@ -1,3 +1,31 @@ interface I { boolean equals(I i); +} +class A { + + public boolean equals(A a) { + return false; + } +} +class B extends A { + + @Override + public boolean equals(A a) { + return super.equals(a); + } +} +class C { + public boolean equals(C c) { + return false; + } + + public boolean equals(Object o) { + return true; + } +} +class D implements I { + @Override + public boolean equals(I i) { + return false; + } } \ No newline at end of file From 6bf3af837e10fe0a46f6e4573e4e6e0916d5155f Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Mon, 4 Jul 2016 21:08:04 +0200 Subject: [PATCH 49/50] fix dotted painting around button --- .../ide/ui/laf/intellij/WinIntelliJButtonPainter.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJButtonPainter.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJButtonPainter.java index e0646ea512ee..a85274185218 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJButtonPainter.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellij/WinIntelliJButtonPainter.java @@ -19,6 +19,7 @@ import com.intellij.ide.ui.laf.darcula.ui.DarculaButtonUI; import com.intellij.openapi.actionSystem.ActionToolbar; import com.intellij.ui.Gray; import com.intellij.util.ui.JBUI; +import com.intellij.util.ui.UIUtil; import javax.swing.*; import javax.swing.border.Border; @@ -52,9 +53,10 @@ public class WinIntelliJButtonPainter implements Border, UIResource { g.translate(x,y); if (hasFocus) { - g.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 1, new float[]{1}, 1)); + //g.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 1, new float[]{1}, 1)); g.setColor(Gray.x0F); - g.drawRect(2*dd, 2*dd, width - 4*dd - 1, height - 4*dd - 1); + UIUtil.drawDottedRectangle(g, 2*dd, 2*dd, width - 2*dd - 1, height - 2*dd - 1); + //g.drawRect(2*dd, 2*dd, width - 4*dd - 1, height - 4*dd - 1); } g.translate(-x,-y); } From da07daf5cedc7532803c78ec56cade5e61ad903d Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 5 Jul 2016 08:57:06 +0200 Subject: [PATCH 50/50] stub hierarchy: use less memory when reading from index --- .../impl/HierarchyServiceImpl.java | 6 +- .../psi/stubsHierarchy/impl/Imports.java | 50 +++- .../stubsHierarchy/impl/NameEnvironment.java | 21 ++ .../stubsHierarchy/impl/SerializedUnit.java | 217 ++++++++++++++++++ .../psi/stubsHierarchy/impl/StubEnter.java | 93 ++------ .../impl/StubHierarchyIndex.java | 35 ++- .../psi/stubsHierarchy/impl/Symbol.java | 16 +- .../java/stubs/index/JavaUnitDescriptor.java | 168 -------------- 8 files changed, 346 insertions(+), 260 deletions(-) create mode 100644 java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/SerializedUnit.java delete mode 100644 java/java-indexing-impl/src/com/intellij/psi/impl/java/stubs/index/JavaUnitDescriptor.java diff --git a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/HierarchyServiceImpl.java b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/HierarchyServiceImpl.java index 50e99120097c..d0d171d7fd2a 100644 --- a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/HierarchyServiceImpl.java +++ b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/HierarchyServiceImpl.java @@ -79,14 +79,14 @@ public class HierarchyServiceImpl extends HierarchyService { } private void loadUnits(BitSet files, int[] indexKeys, StubEnter stubEnter) { - FileBasedIndexImpl.IdValueProcessor processor = new FileBasedIndexImpl.IdValueProcessor() { + FileBasedIndexImpl.IdValueProcessor processor = new FileBasedIndexImpl.IdValueProcessor() { final ProgressIndicator indicator = ProgressIndicatorProvider.getGlobalProgressIndicator(); int count = 0; @Override - public boolean process(int fileId, IndexTree.Unit unit) { + public boolean process(int fileId, SerializedUnit unit) { if (indicator != null && ++count % 128 == 0) indicator.checkCanceled(); if (files.get(fileId)) { - stubEnter.unitEnter(unit, fileId); + unit.readUnit(stubEnter, fileId); } return true; } diff --git a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Imports.java b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Imports.java index 2b1ece3f88a8..baded25636ca 100644 --- a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Imports.java +++ b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Imports.java @@ -15,10 +15,16 @@ */ package com.intellij.psi.stubsHierarchy.impl; +import com.intellij.psi.impl.java.stubs.hierarchy.IndexTree; import com.intellij.util.ArrayUtil; import com.intellij.util.BitUtil; +import com.intellij.util.io.DataInputOutputUtil; +import org.jetbrains.annotations.NotNull; -public class Imports { +import java.io.DataOutput; +import java.io.IOException; + +class Imports { public final static long[] EMPTY_ARRAY = ArrayUtil.EMPTY_LONG_ARRAY; public static final int onDemandMask = 1 << 29; @@ -50,4 +56,46 @@ public class Imports { if (onDemand) lower |= onDemandMask; return (((long)alias) << 32) | lower; } + + private final static int IS_STATIC = 1; + private final static int IS_ON_DEMAND = 2; + private final static int HAS_ALIAS = 4; + + static void writeImports(@NotNull DataOutput out, IndexTree.Unit value) throws IOException { + DataInputOutputUtil.writeINT(out, value.imports.length); + for (IndexTree.Import anImport : value.imports) { + writeImport(out, anImport); + } + } + + static long[] readImports(UnitInputStream in) throws IOException { + int importCount = DataInputOutputUtil.readINT(in); + long[] imports = importCount == 0 ? EMPTY_ARRAY : new long[importCount]; + for (int i = 0; i < importCount; i++) { + imports[i] = readImport(in); + } + return imports; + } + + private static void writeImport(@NotNull DataOutput out, IndexTree.Import anImport) throws IOException { + SerializedUnit.writeQualifiedName(out, anImport.myFullname); + boolean hasAlias = anImport.myAlias != 0; + int flags = 0; + flags = BitUtil.set(flags, IS_STATIC, anImport.myStaticImport); + flags = BitUtil.set(flags, IS_ON_DEMAND, anImport.myOnDemand); + flags = BitUtil.set(flags, HAS_ALIAS, hasAlias); + out.writeByte(flags); + if (hasAlias) { + out.writeInt(anImport.myAlias); + } + } + + private static long readImport(UnitInputStream in) throws IOException { + int fullname = in.names.readQualifiedName(in); + int flags = in.readByte(); + return mkImport(fullname, + BitUtil.isSet(flags, IS_STATIC), BitUtil.isSet(flags, IS_ON_DEMAND), + BitUtil.isSet(flags, HAS_ALIAS) ? in.readInt() : 0); + } + } diff --git a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/NameEnvironment.java b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/NameEnvironment.java index 2c9db64a54c9..048d6fbc9682 100644 --- a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/NameEnvironment.java +++ b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/NameEnvironment.java @@ -18,9 +18,14 @@ package com.intellij.psi.stubsHierarchy.impl; import com.intellij.openapi.util.UserDataHolderBase; import com.intellij.psi.CommonClassNames; import com.intellij.psi.impl.java.stubs.hierarchy.IndexTree; +import com.intellij.util.io.DataInputOutputUtil; import gnu.trove.TIntArrayList; import gnu.trove.TLongIntHashMap; +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + class NameEnvironment extends UserDataHolderBase { public static final int OBJECT_NAME = IndexTree.hashIdentifier("Object"); public static final int NO_NAME = 0; @@ -67,6 +72,22 @@ class NameEnvironment extends UserDataHolderBase { return id; } + /** + * @see SerializedUnit#writeQualifiedName(DataOutput, int[]) + */ + @QNameId int readQualifiedName(DataInput in) throws IOException { + int id = 0; + int len = DataInputOutputUtil.readINT(in); + for (int i = 0; i < len; i++) { + id = qualifiedName(id, in.readInt()); + } + return id; + } + + int memberQualifiedName(@QNameId int ownerName, @ShortName int name) { + return name == NO_NAME || ownerName < 0 ? -1 : qualifiedName(ownerName, name); + } + @QNameId int qualifiedName(@QNameId int prefix, @ShortName int shortName) { int existing = findExistingName(prefix, shortName); return existing >= 0 ? existing : addName(prefix, shortName); diff --git a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/SerializedUnit.java b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/SerializedUnit.java new file mode 100644 index 000000000000..492f30a8fe03 --- /dev/null +++ b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/SerializedUnit.java @@ -0,0 +1,217 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.psi.stubsHierarchy.impl; + +import com.intellij.psi.impl.java.stubs.hierarchy.IndexTree; +import com.intellij.psi.stubsHierarchy.impl.Symbol.ClassSymbol; +import com.intellij.psi.stubsHierarchy.impl.Symbol.MemberSymbol; +import com.intellij.psi.stubsHierarchy.impl.Symbol.PackageSymbol; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.io.DataInputOutputUtil; +import com.intellij.util.io.DataOutputStream; +import com.intellij.util.io.UnsyncByteArrayInputStream; +import com.intellij.util.io.UnsyncByteArrayOutputStream; +import org.jetbrains.annotations.NotNull; + +import java.io.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @author peter + */ +class SerializedUnit { + private final byte[] myBytes; + + SerializedUnit(byte[] bytes) { + myBytes = bytes; + } + + SerializedUnit(IndexTree.Unit unit) { + try { + //noinspection IOResourceOpenedButNotSafelyClosed + UnsyncByteArrayOutputStream stream = new UnsyncByteArrayOutputStream(); + writeUnit(new DataOutputStream(stream), unit); + myBytes = stream.toByteArray(); + } + catch (IOException impossible) { + throw new RuntimeException(impossible); + } + } + + byte[] getSerializedBytes() { + return myBytes; + } + + void readUnit(StubEnter stubEnter, int fileId) { + try { + enterUnit(new UnitInputStream(new UnsyncByteArrayInputStream(myBytes), fileId, stubEnter)); + } + catch (IOException impossible) { + throw new RuntimeException(impossible); + } + } + + /** + * @see NameEnvironment#readQualifiedName(DataInput) + */ + static void writeQualifiedName(DataOutput out, @QNameId int[] array) throws IOException { + DataInputOutputUtil.writeINT(out, array.length); + for (int i : array) { + out.writeInt(i); + } + } + + // unit + + private static void writeUnit(@NotNull DataOutput out, IndexTree.Unit value) throws IOException { + writeQualifiedName(out, value.myPackageName); + out.writeByte(value.myUnitType); + if (value.myUnitType != IndexTree.BYTECODE) { + Imports.writeImports(out, value); + } + // class Declaration + DataInputOutputUtil.writeINT(out, value.myDecls.length); + for (IndexTree.ClassDecl def : value.myDecls) { + saveClassDecl(out, def); + } + } + + private static void enterUnit(UnitInputStream in) throws IOException { + PackageSymbol pkg = in.stubEnter.enterPackage(in); + byte type = in.readByte(); + long[] imports = type == IndexTree.BYTECODE ? Imports.EMPTY_ARRAY : Imports.readImports(in); + UnitInfo unitInfo = UnitInfo.mkUnitInfo(type, imports); + + int classCount = DataInputOutputUtil.readINT(in); + for (int i = 0; i < classCount; i++) { + readClassDecl(in, unitInfo, pkg, pkg.myQualifiedName); + } + } + + // class + + private static void saveClassDecl(@NotNull DataOutput out, IndexTree.ClassDecl value) throws IOException { + DataInputOutputUtil.writeINT(out, value.myStubId); + DataInputOutputUtil.writeINT(out, value.myMods); + out.writeInt(value.myName); + writeSupers(out, value); + writeMembers(out, value.myDecls); + } + + private static ClassSymbol readClassDecl(UnitInputStream in, UnitInfo info, Symbol owner, @QNameId int ownerName) throws IOException { + int stubId = DataInputOutputUtil.readINT(in); + int mods = DataInputOutputUtil.readINT(in); + @ShortName int name = in.readInt(); + @QNameId int[] superNames = readSupers(in); + + @QNameId int qname = in.names.memberQualifiedName(ownerName, name); + ClassSymbol symbol = in.stubEnter.classEnter(info, owner, stubId, mods, name, superNames, qname, in.fileId); + + readMembers(in, info, qname, symbol); + return symbol; + } + + // supers + + private static void writeSupers(@NotNull DataOutput out, IndexTree.ClassDecl value) throws IOException { + DataInputOutputUtil.writeINT(out, value.mySupers.length); + for (int[] aSuper : value.mySupers) { + writeQualifiedName(out, aSuper); + } + } + + private static @QNameId int[] readSupers(UnitInputStream in) throws IOException { + @QNameId int[] superNames = new int[DataInputOutputUtil.readINT(in)]; + for (int i = 0; i < superNames.length; i++) { + superNames[i] = in.names.readQualifiedName(in); + } + return superNames; + } + + // members + + private static void writeMembers(@NotNull DataOutput out, IndexTree.Decl[] decls) throws IOException { + DataInputOutputUtil.writeINT(out, decls.length); + for (IndexTree.Decl def : decls) { + saveDecl(out, def); + } + } + + private static void readMembers(UnitInputStream in, + UnitInfo info, + @QNameId int ownerName, + MemberSymbol symbol) throws IOException { + int memberCount = DataInputOutputUtil.readINT(in); + if (memberCount == 0) return; + + List members = new ArrayList<>(); + for (int i = 0; i < memberCount; i++) { + ContainerUtil.addIfNotNull(members, readDecl(in, info, symbol, ownerName)); + } + symbol.setMembers(members); + } + + // decl: class or member + + private static void saveDecl(@NotNull DataOutput out, IndexTree.Decl value) throws IOException { + if (value instanceof IndexTree.ClassDecl) { + out.writeBoolean(true); + saveClassDecl(out, (IndexTree.ClassDecl)value); + } else if (value instanceof IndexTree.MemberDecl) { + out.writeBoolean(false); + writeMembers(out, ((IndexTree.MemberDecl)value).myDecls); + } + } + + private static ClassSymbol readDecl(UnitInputStream in, UnitInfo info, Symbol owner, @QNameId int ownerName) throws IOException { + if (in.readBoolean()) { + return readClassDecl(in, info, owner, ownerName); + } + + readMembers(in, info, ownerName, new MemberSymbol(owner)); + return null; + } + + @Override + public boolean equals(Object o) { + return this == o || o instanceof SerializedUnit && Arrays.equals(myBytes, ((SerializedUnit)o).myBytes); + } + + @Override + public int hashCode() { + int result = myBytes.length; + int length = Math.min(30, myBytes.length); + for (int i = 0; i < length; i++) { + result = 31 * result + myBytes[i]; + } + return result; + } +} + +class UnitInputStream extends DataInputStream { + final int fileId; + final StubEnter stubEnter; + final NameEnvironment names; + + UnitInputStream(InputStream in, int fileId, StubEnter stubEnter) { + super(in); + this.fileId = fileId; + this.stubEnter = stubEnter; + this.names = stubEnter.myNameEnvironment; + } +} diff --git a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/StubEnter.java b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/StubEnter.java index dcfbe0373dc6..b8d72da404ec 100644 --- a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/StubEnter.java +++ b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/StubEnter.java @@ -19,13 +19,15 @@ import com.intellij.psi.impl.java.stubs.hierarchy.IndexTree; import com.intellij.util.BitUtil; import org.jetbrains.annotations.Nullable; +import java.io.DataInput; +import java.io.IOException; import java.util.ArrayList; -import java.util.Arrays; -import static com.intellij.psi.stubsHierarchy.impl.Symbol.*; +import static com.intellij.psi.stubsHierarchy.impl.Symbol.ClassSymbol; +import static com.intellij.psi.stubsHierarchy.impl.Symbol.PackageSymbol; public class StubEnter { - private final NameEnvironment myNameEnvironment; + final NameEnvironment myNameEnvironment; private final Symbols mySymbols; private final StubHierarchyConnector myStubHierarchyConnector; @@ -37,85 +39,30 @@ public class StubEnter { myStubHierarchyConnector = new StubHierarchyConnector(myNameEnvironment, symbols); } - void unitEnter(IndexTree.Unit unit, int fileId) { - @QNameId int pkgName = unit.myPackageName.length > 0 ? myNameEnvironment.internQualifiedName(unit.myPackageName) : 0; - enter(unit.myDecls, UnitInfo.mkUnitInfo(unit.myUnitType, internImports(unit)), mySymbols.enterPackage(pkgName), pkgName, fileId); + PackageSymbol enterPackage(DataInput in) throws IOException { + return mySymbols.enterPackage(myNameEnvironment.readQualifiedName(in)); } - private long[] internImports(IndexTree.Unit unit) { - long[] imports = unit.imports.length == 0 ? Imports.EMPTY_ARRAY : new long[unit.imports.length]; - for (int i = 0; i < unit.imports.length; i++) { - imports[i] = processImport(unit.imports[i]); - } - return imports; - } - - private long processImport(IndexTree.Import anImport) { - int fullname = myNameEnvironment.internQualifiedName(anImport.myFullname); - return Imports.mkImport(fullname, anImport.myStaticImport, anImport.myOnDemand, anImport.myAlias); - } - - private void enter(IndexTree.ClassDecl[] trees, UnitInfo info, Symbol owner, @QNameId int ownerName, int fileId) { - for (IndexTree.ClassDecl tree : trees) { - enter(tree, info, owner, ownerName, fileId); - } - } - - private ClassSymbol[] enter(IndexTree.Decl[] trees, UnitInfo info, Symbol owner, @QNameId int ownerName, int fileId) { - ClassSymbol[] members = new ClassSymbol[trees.length]; - int i = 0; - for (IndexTree.Decl tree : trees) { - ClassSymbol member = enter(tree, info, owner, ownerName, fileId); - if (member != null && member.myShortName != 0) { - members[i++] = member; - } - } - if (i == 0) return ClassSymbol.EMPTY_ARRAY; - - if (i < members.length) { - members = Arrays.copyOf(members, i); - } - Arrays.sort(members, CLASS_SYMBOL_BY_NAME_COMPARATOR); - return members; - } - - private ClassSymbol enter(IndexTree.Decl tree, UnitInfo info, Symbol owner, @QNameId int ownerName, int fileId) { - if (tree instanceof IndexTree.ClassDecl) { - return classEnter((IndexTree.ClassDecl)tree, info, owner, ownerName, fileId); - } - if (tree instanceof IndexTree.MemberDecl) { - memberEnter((IndexTree.MemberDecl)tree, info, owner, ownerName, fileId); - return null; - } - return null; - } - - private void memberEnter(IndexTree.MemberDecl tree, UnitInfo info, Symbol owner, @QNameId int ownerName, int fileId) { - MemberSymbol mc = new MemberSymbol(owner); - mc.setMembers(enter(tree.myDecls, info, mc, ownerName, fileId)); - } - - private ClassSymbol classEnter(IndexTree.ClassDecl tree, UnitInfo info, Symbol owner, @QNameId int ownerName, int fileId) { - int flags = checkFlags(tree.myMods, owner, info.getType() == IndexTree.BYTECODE); - - int name = tree.myName; - @QNameId int qname = name == NameEnvironment.NO_NAME || ownerName < 0 ? -1 - : myNameEnvironment.qualifiedName(ownerName, name); - @CompactArray(QualifiedName.class) Object supers = internSupers(tree.myMods, tree.mySupers); - ClassSymbol classSymbol = mySymbols.enterClass(fileId, tree.myStubId, flags, name, owner, info, supers, qname); + ClassSymbol classEnter(UnitInfo info, + Symbol owner, + int stubId, + int mods, + @ShortName int name, + @QNameId int[] superNames, + @QNameId int qname, int fileId) throws IOException { + int flags = checkFlags(mods, owner, info.getType() == IndexTree.BYTECODE); + @CompactArray(QualifiedName.class) Object supers = internSupers(mods, superNames); + ClassSymbol classSymbol = mySymbols.enterClass(fileId, stubId, flags, name, owner, info, supers, qname); if (uncompleted != null) { uncompleted.add(classSymbol); } - if (tree.myDecls.length > 0) { - classSymbol.setMembers(enter(tree.myDecls, info, classSymbol, qname, fileId)); - } return classSymbol; } @Nullable @CompactArray(QualifiedName.class) - private Object internSupers(int flags, int[][] superNames) { + Object internSupers(int flags, int[] superNames) { if (BitUtil.isSet(flags, IndexTree.ANNOTATION)) { return myNameEnvironment.java_lang_annotation_Annotation; } @@ -125,12 +72,12 @@ public class StubEnter { return isEnum ? myNameEnvironment.java_lang_Enum : null; } if (superNames.length == 1 && !isEnum) { - return new QualifiedName(myNameEnvironment.internQualifiedName(superNames[0])); + return new QualifiedName(superNames[0]); } QualifiedName[] array = new QualifiedName[superNames.length + (isEnum ? 1 : 0)]; for (int i = 0; i < superNames.length; i++) { - array[i] = new QualifiedName(myNameEnvironment.internQualifiedName(superNames[i])); + array[i] = new QualifiedName(superNames[i]); } if (isEnum) { array[array.length - 1] = myNameEnvironment.java_lang_Enum; diff --git a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/StubHierarchyIndex.java b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/StubHierarchyIndex.java index 057b7160aa0c..2de47735eaf4 100644 --- a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/StubHierarchyIndex.java +++ b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/StubHierarchyIndex.java @@ -21,14 +21,17 @@ import com.intellij.openapi.roots.ProjectFileIndex; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileWithId; import com.intellij.psi.impl.java.stubs.hierarchy.IndexTree; -import com.intellij.psi.impl.java.stubs.index.JavaUnitDescriptor; import com.intellij.psi.stubsHierarchy.StubHierarchyIndexer; import com.intellij.util.indexing.*; import com.intellij.util.io.DataExternalizer; +import com.intellij.util.io.DataInputOutputUtil; import com.intellij.util.io.EnumeratorIntegerDescriptor; import com.intellij.util.io.KeyDescriptor; import org.jetbrains.annotations.NotNull; +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; import java.util.Arrays; import java.util.Collections; import java.util.stream.IntStream; @@ -36,29 +39,29 @@ import java.util.stream.IntStream; /** * @author peter */ -public class StubHierarchyIndex extends FileBasedIndexExtension implements PsiDependentIndex { +public class StubHierarchyIndex extends FileBasedIndexExtension implements PsiDependentIndex { private static final int KEY_COUNT = 20; static final int[] BINARY_KEYS = IntStream.rangeClosed(1, KEY_COUNT).toArray(); static final int[] SOURCE_KEYS = IntStream.rangeClosed(-KEY_COUNT, -1).toArray(); - static final ID INDEX_ID = ID.create("jvm.hierarchy"); + static final ID INDEX_ID = ID.create("jvm.hierarchy"); private static final StubHierarchyIndexer[] ourIndexers = StubHierarchyIndexer.EP_NAME.getExtensions(); @NotNull @Override - public ID getName() { + public ID getName() { return INDEX_ID; } @NotNull @Override - public DataIndexer getIndexer() { + public DataIndexer getIndexer() { return inputData -> { for (StubHierarchyIndexer indexer : ourIndexers) { VirtualFile file = inputData.getFile(); IndexTree.Unit unit = indexer.handlesFile(file) ? indexer.indexFile(inputData) : null; if (unit != null && unit.myDecls.length > 0) { int[] keys = file.getFileType().isBinary() ? BINARY_KEYS : SOURCE_KEYS; - return Collections.singletonMap(keys[((VirtualFileWithId) file).getId() % keys.length], unit); + return Collections.singletonMap(keys[((VirtualFileWithId) file).getId() % keys.length], new SerializedUnit(unit)); } } return Collections.emptyMap(); @@ -73,13 +76,27 @@ public class StubHierarchyIndex extends FileBasedIndexExtension getValueExternalizer() { - return JavaUnitDescriptor.INSTANCE; + public DataExternalizer getValueExternalizer() { + return new DataExternalizer() { + @Override + public void save(@NotNull DataOutput out, SerializedUnit value) throws IOException { + byte[] bytes = value.getSerializedBytes(); + DataInputOutputUtil.writeINT(out, bytes.length); + out.write(bytes); + } + + @Override + public SerializedUnit read(@NotNull DataInput in) throws IOException { + byte[] bytes = new byte[DataInputOutputUtil.readINT(in)]; + in.readFully(bytes); + return new SerializedUnit(bytes); + } + }; } @Override public int getVersion() { - return IndexTree.STUB_HIERARCHY_ENABLED ? 5 + Arrays.stream(ourIndexers).mapToInt(StubHierarchyIndexer::getVersion).sum() : 0; + return IndexTree.STUB_HIERARCHY_ENABLED ? 6 + Arrays.stream(ourIndexers).mapToInt(StubHierarchyIndexer::getVersion).sum() : 0; } @NotNull diff --git a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Symbol.java b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Symbol.java index 20f5bb1116c3..ed438237d753 100644 --- a/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Symbol.java +++ b/java/java-impl/src/com/intellij/psi/stubsHierarchy/impl/Symbol.java @@ -21,9 +21,7 @@ import gnu.trove.TIntHashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Collections; -import java.util.Comparator; -import java.util.Set; +import java.util.*; /** * Java symbols needed for hierarchy building. Mostly classes ({@link ClassSymbol}) or packages ({@link PackageSymbol}), @@ -200,12 +198,18 @@ public abstract class Symbol { (ClassSymbol[])myMembers; } - void setMembers(ClassSymbol[] members) { - myMembers = members.length == 0 ? null : members.length == 1 ? members[0] : members; + void setMembers(List members) { + myMembers = members.isEmpty() ? null : members.size() == 1 ? members.get(0) : toSortedArray(members); + } + + private static ClassSymbol[] toSortedArray(List members) { + ClassSymbol[] array = members.toArray(new ClassSymbol[members.size()]); + Arrays.sort(array, CLASS_SYMBOL_BY_NAME_COMPARATOR); + return array; } } - public static final Comparator CLASS_SYMBOL_BY_NAME_COMPARATOR = (s1, s2) -> { + private static final Comparator CLASS_SYMBOL_BY_NAME_COMPARATOR = (s1, s2) -> { int name1 = s1.myShortName; int name2 = s2.myShortName; return (name1 < name2) ? -1 : ((name1 == name2) ? 0 : 1); diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/java/stubs/index/JavaUnitDescriptor.java b/java/java-indexing-impl/src/com/intellij/psi/impl/java/stubs/index/JavaUnitDescriptor.java deleted file mode 100644 index ad2fddadbe36..000000000000 --- a/java/java-indexing-impl/src/com/intellij/psi/impl/java/stubs/index/JavaUnitDescriptor.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright 2000-2015 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * 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.psi.impl.java.stubs.index; - -import com.intellij.psi.impl.java.stubs.hierarchy.IndexTree; -import com.intellij.util.BitUtil; -import com.intellij.util.io.DataExternalizer; -import com.intellij.util.io.DataInputOutputUtil; -import org.jetbrains.annotations.NotNull; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -import static com.intellij.psi.impl.java.stubs.index.JavaUnitDescriptor.ImportFlags.*; - -public class JavaUnitDescriptor implements DataExternalizer { - public static final JavaUnitDescriptor INSTANCE = new JavaUnitDescriptor(); - - private static void writeIntArray(DataOutput out, int[] array) throws IOException { - DataInputOutputUtil.writeINT(out, array.length); - for (int i : array) { - out.writeInt(i); - } - } - private static int[] readIntArray(DataInput in) throws IOException { - int length = DataInputOutputUtil.readINT(in); - int[] result = new int[length]; - for (int i = 0; i < length; i++) { - result[i] = in.readInt(); - } - return result; - } - - @Override - public void save(@NotNull DataOutput out, IndexTree.Unit value) throws IOException { - writeIntArray(out, value.myPackageName); - out.writeByte(value.myUnitType); - if (value.myUnitType != IndexTree.BYTECODE) { - DataInputOutputUtil.writeINT(out, value.imports.length); - for (IndexTree.Import anImport : value.imports) { - writeImport(out, anImport); - } - } - // class Declaration - DataInputOutputUtil.writeINT(out, value.myDecls.length); - for (IndexTree.ClassDecl def : value.myDecls) { - saveClassDecl(out, def); - } - } - - private void saveClassDecl(@NotNull DataOutput out, IndexTree.ClassDecl value) throws IOException { - DataInputOutputUtil.writeINT(out, value.myStubId); - DataInputOutputUtil.writeINT(out, value.myMods); - out.writeInt(value.myName); - DataInputOutputUtil.writeINT(out, value.mySupers.length); - for (int[] aSuper : value.mySupers) { - writeIntArray(out, aSuper); - } - DataInputOutputUtil.writeINT(out, value.myDecls.length); - for (IndexTree.Decl def : value.myDecls) { - saveDecl(out, def); - } - } - - private void saveDecl(@NotNull DataOutput out, IndexTree.Decl value) throws IOException { - if (value instanceof IndexTree.ClassDecl) { - out.writeBoolean(true); - saveClassDecl(out, (IndexTree.ClassDecl)value); - } else if (value instanceof IndexTree.MemberDecl) { - out.writeBoolean(false); - IndexTree.MemberDecl memberDecl = (IndexTree.MemberDecl)value; - DataInputOutputUtil.writeINT(out, memberDecl.myDecls.length); - for (IndexTree.Decl def : memberDecl.myDecls) { - saveDecl(out, def); - } - } - } - - @Override - public IndexTree.Unit read(@NotNull DataInput in) throws IOException { - int[] pid = readIntArray(in); - byte type = in.readByte(); - IndexTree.Import[] imports = IndexTree.Import.EMPTY_ARRAY; - if (type != IndexTree.BYTECODE) { - imports = new IndexTree.Import[DataInputOutputUtil.readINT(in)]; - for (int i = 0; i < imports.length; i++) { - imports[i] = readImport(in); - } - } - IndexTree.ClassDecl[] classes = new IndexTree.ClassDecl[DataInputOutputUtil.readINT(in)]; - for (int i = 0; i < classes.length; i++) { - classes[i] = readClassDecl(in); - } - return new IndexTree.Unit(pid, type, imports, classes); - } - - private IndexTree.ClassDecl readClassDecl(DataInput in) throws IOException { - int stubId = DataInputOutputUtil.readINT(in); - int mods = DataInputOutputUtil.readINT(in); - int name = in.readInt(); - int[][] supers = new int[DataInputOutputUtil.readINT(in)][]; - for (int i = 0; i < supers.length; i++) { - supers[i] = readIntArray(in); - } - IndexTree.Decl[] decls = new IndexTree.Decl[DataInputOutputUtil.readINT(in)]; - for (int i = 0; i < decls.length; i++) { - decls[i] = readDecl(in); - } - return new IndexTree.ClassDecl(stubId, mods, name, supers, decls); - } - - private IndexTree.Decl readDecl(DataInput in) throws IOException { - boolean isClassDecl = in.readBoolean(); - if (isClassDecl) { - return readClassDecl(in); - } - else { - IndexTree.Decl[] decls = new IndexTree.Decl[DataInputOutputUtil.readINT(in)]; - for (int i = 0; i < decls.length; i++) { - decls[i] = readDecl(in); - } - return new IndexTree.MemberDecl(decls); - } - } - - interface ImportFlags { - int IS_STATIC = 1; - int IS_ON_DEMAND = 2; - int HAS_ALIAS = 4; - } - - private static void writeImport(@NotNull DataOutput out, IndexTree.Import anImport) throws IOException { - writeIntArray(out, anImport.myFullname); - boolean hasAlias = anImport.myAlias != 0; - int flags = 0; - flags = BitUtil.set(flags, IS_STATIC, anImport.myStaticImport); - flags = BitUtil.set(flags, IS_ON_DEMAND, anImport.myOnDemand); - flags = BitUtil.set(flags, HAS_ALIAS, hasAlias); - out.writeByte(flags); - if (hasAlias) { - out.writeInt(anImport.myAlias); - } - } - - @NotNull - private static IndexTree.Import readImport(@NotNull DataInput in) throws IOException { - int[] fullname = readIntArray(in); - int flags = in.readByte(); - return new IndexTree.Import(fullname, - BitUtil.isSet(flags, IS_STATIC), BitUtil.isSet(flags, IS_ON_DEMAND), - BitUtil.isSet(flags, HAS_ALIAS) ? in.readInt() : 0); - } - -}