From 5e108a9f99ad7aaf549f547b57a0291ed3531275 Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Mon, 4 Jul 2016 13:11:12 +0300 Subject: [PATCH 01/21] global inspection engine: synchronization issues (redundant "synchronized" keyword) --- .../intellij/codeInspection/ex/GlobalInspectionContextImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextImpl.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextImpl.java index 67428c29d8e3..ec45dc1d1a97 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextImpl.java @@ -120,7 +120,7 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp myTreeState = treeState; } - public synchronized void addView(@NotNull InspectionResultsView view, + public void addView(@NotNull InspectionResultsView view, @NotNull String title, boolean isOffline) { LOG.assertTrue(myContent == null, "GlobalInspectionContext is busy under other view now"); From da07daf5cedc7532803c78ec56cade5e61ad903d Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 5 Jul 2016 08:57:06 +0200 Subject: [PATCH 02/21] 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); - } - -} From 20bf5a9927618384d61734729c69fdee0c56c359 Mon Sep 17 00:00:00 2001 From: Dmitry Batkovich Date: Tue, 5 Jul 2016 10:09:29 +0300 Subject: [PATCH 03/21] inspections: clear redundant spaces while #ref macros substitution --- .../codeInspection/ProblemDescriptorUtil.java | 38 ++++++++++++++++++- .../ProblemDescriptorUtilTest.java | 36 ++++++++++++++++++ .../MissortedModifiers.java | 2 +- 3 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 platform/platform-tests/testSrc/com/intellij/codeInspection/ProblemDescriptorUtilTest.java diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/ProblemDescriptorUtil.java b/platform/analysis-impl/src/com/intellij/codeInspection/ProblemDescriptorUtil.java index 47eb271344ea..dc3210f54ca1 100644 --- a/platform/analysis-impl/src/com/intellij/codeInspection/ProblemDescriptorUtil.java +++ b/platform/analysis-impl/src/com/intellij/codeInspection/ProblemDescriptorUtil.java @@ -57,7 +57,7 @@ public class ProblemDescriptorUtil { } ref = StringUtil.replaceChar(ref, '\n', ' ').trim(); ref = StringUtil.first(ref, 100, true); - return ref; + return clearDuplicatedWhitespaces(ref); } @NotNull @@ -181,4 +181,40 @@ public class ProblemDescriptorUtil { } throw new RuntimeException("Cannot map " + highlightType); } + + static String clearDuplicatedWhitespaces(@NotNull String input) { + if (input.isEmpty()) { + return input; + } + char[] refWithoutRedundantSpaces = null; + int tail = 0; + for (int i = 0; i < input.length() - 1; i++) { + final char c1 = input.charAt(i); + final char c2 = input.charAt(i+1); + final boolean isWhiteSpace1 = StringUtil.isWhiteSpace(c1); + final boolean isWhiteSpace2 = StringUtil.isWhiteSpace(c2); + if (isWhiteSpace1 && isWhiteSpace2) { + if (refWithoutRedundantSpaces == null) { + refWithoutRedundantSpaces = new char[input.length()]; + for (int j = 0; j < i; j++) { + refWithoutRedundantSpaces[j] = input.charAt(j); + } + tail = i; + } + } + else if (refWithoutRedundantSpaces != null) { + refWithoutRedundantSpaces[tail++] = isWhiteSpace1 ? ' ' : c1; + } + } + final char lastChar = input.charAt(input.length() - 1); + final boolean isLastWhiteSpace = StringUtil.isWhiteSpace(lastChar); + if (refWithoutRedundantSpaces != null) { + if (!isLastWhiteSpace) { + refWithoutRedundantSpaces[tail++] = lastChar; + } + } else if (isLastWhiteSpace) { + return new String(input.toCharArray(), 0, input.length() - 1); + } + return refWithoutRedundantSpaces == null ? input : new String(refWithoutRedundantSpaces, 0, tail); + } } diff --git a/platform/platform-tests/testSrc/com/intellij/codeInspection/ProblemDescriptorUtilTest.java b/platform/platform-tests/testSrc/com/intellij/codeInspection/ProblemDescriptorUtilTest.java new file mode 100644 index 000000000000..c33a119b8637 --- /dev/null +++ b/platform/platform-tests/testSrc/com/intellij/codeInspection/ProblemDescriptorUtilTest.java @@ -0,0 +1,36 @@ +/* + * 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.codeInspection; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * @author Dmitry Batkovich + */ +public class ProblemDescriptorUtilTest { + + @Test + public void testClearDuplicatedWhiteSpaces() { + assertEquals("", ProblemDescriptorUtil.clearDuplicatedWhitespaces("")); + assertEquals("some text is here", ProblemDescriptorUtil.clearDuplicatedWhitespaces("some text is here")); + assertEquals("some text is here", ProblemDescriptorUtil.clearDuplicatedWhitespaces("some text is here ")); + assertEquals("some text is here", ProblemDescriptorUtil.clearDuplicatedWhitespaces("some text is here ")); + assertEquals("some text is here", ProblemDescriptorUtil.clearDuplicatedWhitespaces("some \t\t text\tis\t\t\t\t\there")); + assertEquals("sometextishere", ProblemDescriptorUtil.clearDuplicatedWhitespaces("sometextishere")); + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/style/missorted_modifiers/MissortedModifiers.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/missorted_modifiers/MissortedModifiers.java index 69ded8322614..747fb6a83df1 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/style/missorted_modifiers/MissortedModifiers.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/missorted_modifiers/MissortedModifiers.java @@ -43,7 +43,7 @@ class MissortedModifiers { //@Type(type = "org.joda.time.contrib.hibernate.PersistentYearMonthDay") //@Column(name = "current_month") - final + final public @Nullable // commment From c4488e83e6db6bd24a61a2f0c41a97c30282fdca Mon Sep 17 00:00:00 2001 From: Alexander Kass Date: Tue, 5 Jul 2016 10:31:33 +0300 Subject: [PATCH 04/21] JBListTableModel: allow nested model modifications --- .../intellij/util/ui/table/JBListTableModel.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/util/ui/table/JBListTableModel.java b/platform/platform-impl/src/com/intellij/util/ui/table/JBListTableModel.java index 3f4b99b354c2..dae5f3c162c7 100644 --- a/platform/platform-impl/src/com/intellij/util/ui/table/JBListTableModel.java +++ b/platform/platform-impl/src/com/intellij/util/ui/table/JBListTableModel.java @@ -17,6 +17,7 @@ package com.intellij.util.ui.table; import com.intellij.util.ui.EditableModel; +import javax.swing.event.TableModelEvent; import javax.swing.table.AbstractTableModel; import javax.swing.table.TableModel; @@ -28,6 +29,13 @@ public abstract class JBListTableModel extends AbstractTableModel implements Edi public JBListTableModel(TableModel model) { myModel = model; + myModel.addTableModelListener(e -> + fireTableChanged( + new TableModelEvent( + this, e.getFirstRow(), e.getLastRow(), e.getColumn(), e.getType() + ) + ) + ); } @Override @@ -63,18 +71,13 @@ public abstract class JBListTableModel extends AbstractTableModel implements Edi for (int i = 0; i < myModel.getColumnCount(); i++) { myModel.setValueAt(((JBTableRow)value).getValueAt(i), row, i); } - fireTableCellUpdated(row, column); } @Override public void addRow() { - final int count = myModel.getRowCount(); if (myModel instanceof EditableModel) { ((EditableModel)myModel).addRow(); } - if (count < myModel.getRowCount()) { - fireTableRowsInserted(count, myModel.getRowCount() - 1); - } } @Override @@ -82,7 +85,6 @@ public abstract class JBListTableModel extends AbstractTableModel implements Edi if (myModel instanceof EditableModel) { ((EditableModel)myModel).removeRow(index); } - fireTableRowsDeleted(index, index); } @Override @@ -98,6 +100,5 @@ public abstract class JBListTableModel extends AbstractTableModel implements Edi if (myModel instanceof EditableModel) { ((EditableModel)myModel).exchangeRows(oldIndex, newIndex); } - fireTableRowsUpdated(Math.min(oldIndex, newIndex), Math.max(oldIndex, newIndex)); } } From 463627434dcf166567b7b727dc1f20871fc246aa Mon Sep 17 00:00:00 2001 From: Sergey Ignatov Date: Tue, 5 Jul 2016 11:56:20 +0300 Subject: [PATCH 05/21] EA-83400 - IAE: GotoActionModel$ActionWrapper. --- .../intellij/ide/util/gotoByName/GotoActionItemProvider.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionItemProvider.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionItemProvider.java index 725e8b0b21b3..97d149873086 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionItemProvider.java +++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionItemProvider.java @@ -86,8 +86,9 @@ public class GotoActionItemProvider implements ChooseByNameItemProvider { private boolean processAbbreviations(final String pattern, Processor consumer, DataContext context) { List actionIds = AbbreviationManager.getInstance().findActions(pattern); JBIterable wrappers = JBIterable.from(actionIds) - .transform(actionId -> { - AnAction action = myActionManager.getAction(actionId); + .transform(myActionManager::getAction) + .filter(Condition.NOT_NULL) + .transform(action -> { ActionWrapper wrapper = new ActionWrapper(action, myModel.myActionGroups.get(action), MatchMode.NAME, context); return new MatchedValue(wrapper, pattern) { @Nullable From ad9792254e8e402af05fd7da63e2861a3e86e512 Mon Sep 17 00:00:00 2001 From: Dmitry Batrak Date: Tue, 5 Jul 2016 12:51:27 +0300 Subject: [PATCH 06/21] IDEA-111169 Selecting lines using drag over line numbers area forgets last line of selection, if Shift is pressed before release --- .../openapi/editor/impl/EditorImpl.java | 11 +--- .../openapi/editor/impl/EditorImplTest.java | 7 +++ .../fixtures/EditorMouseFixture.java | 59 ++++++++++++------- 3 files changed, 47 insertions(+), 30 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java index 71610987968b..f579d8c7faaf 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java @@ -5726,8 +5726,6 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi } private class MyMouseAdapter extends MouseAdapter { - private boolean mySelectionTweaked; - @Override public void mousePressed(@NotNull MouseEvent e) { requestFocus(); @@ -5769,7 +5767,6 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi clearDraggedRange(); - mySelectionTweaked = false; myMousePressedEvent = e; EditorMouseEvent event = new EditorMouseEvent(EditorImpl.this, e, getMouseEventArea(e)); @@ -5827,9 +5824,6 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi myMultiSelectionInProgress = false; myDragOnGutterSelectionStartLine = -1; - if (!mySelectionTweaked) { - tweakSelectionIfNecessary(e); - } if (e.isConsumed()) { return; } @@ -5929,10 +5923,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi if (eventArea == EditorMouseEventArea.LINE_MARKERS_AREA || eventArea == EditorMouseEventArea.ANNOTATIONS_AREA || eventArea == EditorMouseEventArea.LINE_NUMBERS_AREA) { - if (tweakSelectionIfNecessary(e)) { - mySelectionTweaked = true; - } - else { + if (!tweakSelectionIfNecessary(e)) { myGutterComponent.mousePressed(e); } if (e.isConsumed()) return false; diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/EditorImplTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/EditorImplTest.java index fdb4f286dc68..dba5e6acec81 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/EditorImplTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/editor/impl/EditorImplTest.java @@ -405,4 +405,11 @@ public class EditorImplTest extends AbstractEditorTest { assertEquals(7, highlighters[0].getStartOffset()); assertEquals(8, highlighters[0].getEndOffset()); } + + public void testShiftPressedBeforeDragOverLineNumbersIsFinished() throws Exception { + initText("abc\ndef\nghi"); + EditorTestUtil.setEditorVisibleSize(myEditor, 1000, 1000); // enable drag testing + mouse().pressAtLineNumbers(0).dragToLineNumbers(2).shift().release(); + checkResultByText("abc\ndef\nghi"); + } } diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/EditorMouseFixture.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/EditorMouseFixture.java index 3689d7953dcc..9f7967c626d0 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/EditorMouseFixture.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/EditorMouseFixture.java @@ -33,6 +33,7 @@ public class EditorMouseFixture { private int myModifiers; private int myButton = MouseEvent.BUTTON1; private int myLastId; + private Component myLastComponent; public EditorMouseFixture(EditorImpl editor) { myEditor = editor; @@ -46,9 +47,18 @@ public class EditorMouseFixture { return pressAt(1, getPoint(visualLine, visualColumn)); } + public EditorMouseFixture pressAtLineNumbers(int visualLine) { + assert myEditor.getSettings().isLineNumbersShown(); + return pressAt(myEditor.getGutterComponentEx(), 1, new Point(0, myEditor.visibleLineToY(visualLine))); + } + private EditorMouseFixture pressAt(int clickCount, Point p) { JComponent component = myEditor.getContentComponent(); - component.dispatchEvent(new MouseEvent(component, + return pressAt(component, clickCount, p); + } + + private EditorMouseFixture pressAt(Component component, int clickCount, Point p) { + component.dispatchEvent(new MouseEvent(myLastComponent = component, myLastId = MouseEvent.MOUSE_PRESSED, System.currentTimeMillis(), getModifiers(), @@ -66,27 +76,27 @@ public class EditorMouseFixture { private EditorMouseFixture release(int clickCount) { int oldLastId = myLastId; - JComponent component = myEditor.getContentComponent(); - component.dispatchEvent(new MouseEvent(component, - myLastId = MouseEvent.MOUSE_RELEASED, - System.currentTimeMillis(), - getModifiers(), - myX, - myY, - clickCount, - false, - myButton)); + myLastComponent.dispatchEvent(new MouseEvent(myLastComponent, + myLastId = MouseEvent.MOUSE_RELEASED, + System.currentTimeMillis(), + getModifiers(), + myX, + myY, + clickCount, + false, + myButton)); if (oldLastId == MouseEvent.MOUSE_PRESSED) { - component.dispatchEvent(new MouseEvent(component, - myLastId = MouseEvent.MOUSE_CLICKED, - System.currentTimeMillis(), - getModifiers(), - myX, - myY, - clickCount, - false, - myButton)); + myLastComponent.dispatchEvent(new MouseEvent(myLastComponent, + myLastId = MouseEvent.MOUSE_CLICKED, + System.currentTimeMillis(), + getModifiers(), + myX, + myY, + clickCount, + false, + myButton)); } + myLastComponent = null; return this; } @@ -107,10 +117,19 @@ public class EditorMouseFixture { return dragToXY(p.x, p.y); } + public EditorMouseFixture dragToLineNumbers(int visualLine) { + assert myEditor.getSettings().isLineNumbersShown(); + return dragToXY(myEditor.getGutterComponentEx(), 0, myEditor.visibleLineToY(visualLine)); + } + public EditorMouseFixture dragToXY(int x, int y) { Assert.assertFalse("Cannot test mouse dragging: editor visible size is not set. Use EditorTestUtil.setEditorVisibleSize(width, height)", myEditor.getScrollingModel().getVisibleArea().isEmpty()); JComponent component = myEditor.getContentComponent(); + return dragToXY(component, x, y); + } + + private EditorMouseFixture dragToXY(JComponent component, int x, int y) { component.dispatchEvent(new MouseEvent(component, myLastId = MouseEvent.MOUSE_DRAGGED, System.currentTimeMillis(), From 2dd6464132d2fdc8fd297efaf2d8be4f32a709db Mon Sep 17 00:00:00 2001 From: Valentin Fondaratov Date: Tue, 5 Jul 2016 13:39:59 +0300 Subject: [PATCH 07/21] EA-85603 fix unconditional cast which fails in incorrect YAML docs --- .../breadcrumbs/YAMLBreadcrumbsInfoProvider.java | 6 +++--- .../yaml/breadcrumbs/YAMLBreadcrumbsTest.java | 12 +++++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/plugins/yaml/src/org/jetbrains/yaml/breadcrumbs/YAMLBreadcrumbsInfoProvider.java b/plugins/yaml/src/org/jetbrains/yaml/breadcrumbs/YAMLBreadcrumbsInfoProvider.java index b0aabd62075a..7827980caf28 100644 --- a/plugins/yaml/src/org/jetbrains/yaml/breadcrumbs/YAMLBreadcrumbsInfoProvider.java +++ b/plugins/yaml/src/org/jetbrains/yaml/breadcrumbs/YAMLBreadcrumbsInfoProvider.java @@ -56,11 +56,11 @@ public class YAMLBreadcrumbsInfoProvider extends BreadcrumbsInfoProvider { return ((YAMLKeyValue)e).getKeyText() + ':'; } if (e instanceof YAMLSequenceItem) { - final YAMLSequence parent = (YAMLSequence)e.getParent(); - if (parent == null) { + final PsiElement parent = e.getParent(); + if (!(parent instanceof YAMLSequence)) { return "Item"; } - final List items = parent.getItems(); + final List items = ((YAMLSequence)parent).getItems(); return "Item " + getIndexOf(items, e); } if (e instanceof YAMLScalar) { diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/breadcrumbs/YAMLBreadcrumbsTest.java b/plugins/yaml/testSrc/org/jetbrains/yaml/breadcrumbs/YAMLBreadcrumbsTest.java index 94a89d9fbdaf..bff722295383 100644 --- a/plugins/yaml/testSrc/org/jetbrains/yaml/breadcrumbs/YAMLBreadcrumbsTest.java +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/breadcrumbs/YAMLBreadcrumbsTest.java @@ -61,12 +61,18 @@ public class YAMLBreadcrumbsTest extends LightPlatformCodeInsightFixtureTestCase "bar: asjdjkas,\n" + "baz: [foo: qoo, boo: foo, doo: 123]\n" + "}\n" + + "---\n" + + "foo: \n" + + " bar:\n" + + "- avr\n" + "..."; - private static final String OUTPUT = "[Document 1/2;null][items:;null][Item 2/2;null][descrip:;null][High Heeled \"Ruby\" S...;null]\n" + + private static final String OUTPUT = "[Document 1/3;null][items:;null][Item 2/2;null][descrip:;null][High Heeled \"Ruby\" S...;null]\n" + "------\n" + - "[Document 1/2;null][specialDelivery:;null][Follow the Yellow Br...;null]\n" + + "[Document 1/3;null][specialDelivery:;null][Follow the Yellow Br...;null]\n" + "------\n" + - "[Document 2/2;null][baz:;null][Item 2/3;null][boo:;null][foo;null]"; + "[Document 2/3;null][baz:;null][Item 2/3;null][boo:;null][foo;null]\n" + + "------\n" + + "[Document 3/3;null][foo:;null][Item;null][avr;null]"; public void testAll() { myFixture.configureByText(YAMLFileType.YML, INPUT); From 53434add7411c7e95a1f2b07940fefd64d3396d4 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Mon, 4 Jul 2016 17:28:40 +0300 Subject: [PATCH 08/21] EA-83611 - CCE: DocumentCommitThread$.fun --- .../com/intellij/psi/impl/DocumentCommitThread.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/platform/core-impl/src/com/intellij/psi/impl/DocumentCommitThread.java b/platform/core-impl/src/com/intellij/psi/impl/DocumentCommitThread.java index e7cb267010f3..e29dee5ed92c 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/DocumentCommitThread.java +++ b/platform/core-impl/src/com/intellij/psi/impl/DocumentCommitThread.java @@ -40,10 +40,7 @@ import com.intellij.pom.event.PomModelEvent; import com.intellij.pom.impl.PomTransactionBase; import com.intellij.pom.tree.TreeAspect; import com.intellij.pom.tree.TreeAspectEvent; -import com.intellij.psi.FileViewProvider; -import com.intellij.psi.PsiDocumentManager; -import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiLock; +import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.impl.source.PsiFileImpl; import com.intellij.psi.impl.source.text.DiffLog; @@ -164,7 +161,7 @@ public class DocumentCommitThread implements Runnable, Disposable, DocumentCommi // under lock private void wakeUpQueue() { if (!isDisposed && !documentsToCommit.isEmpty()) { - executor.execute(this); + executor.execute(ProgressManager.getInstance().longProcess("Commit documents", this)); } } @@ -182,6 +179,9 @@ public class DocumentCommitThread implements Runnable, Disposable, DocumentCommi if (!project.isInitialized()) return; PsiFile psiFile = PsiDocumentManager.getInstance(project).getCachedPsiFile(document); if (psiFile == null) return; + if (psiFile instanceof PsiCompiledFile) { + throw new IllegalArgumentException("Can't commit ClsFile: "+psiFile); + } doQueue(project, document, getAllFileNodes(psiFile), reason, currentModalityState); } From 3d721bdfca6bcb5b8270609c142d8028659caf08 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Mon, 4 Jul 2016 18:26:11 +0300 Subject: [PATCH 09/21] notnull --- jps/jps-builders/src/org/jetbrains/jps/cmdline/LogSetup.java | 4 +++- .../src/org/jetbrains/jps/gant/JpsGantProjectBuilder.java | 3 ++- .../src/org/jetbrains/jps/gant/Log4jFileLoggerFactory.java | 4 +++- .../platform-impl/src/com/intellij/idea/LoggerFactory.java | 4 +++- .../src/com/intellij/testFramework/TestLoggerFactory.java | 3 ++- .../src/com/intellij/openapi/diagnostic/Log4jBasedLogger.java | 2 +- 6 files changed, 14 insertions(+), 6 deletions(-) diff --git a/jps/jps-builders/src/org/jetbrains/jps/cmdline/LogSetup.java b/jps/jps-builders/src/org/jetbrains/jps/cmdline/LogSetup.java index cac49042941c..cdcc4374933d 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/cmdline/LogSetup.java +++ b/jps/jps-builders/src/org/jetbrains/jps/cmdline/LogSetup.java @@ -21,6 +21,7 @@ import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.SystemProperties; import org.apache.log4j.PropertyConfigurator; +import org.jetbrains.annotations.NotNull; import org.jetbrains.jps.api.GlobalOptions; import java.io.*; @@ -83,8 +84,9 @@ public class LogSetup { } private static class MyLoggerFactory implements Logger.Factory { + @NotNull @Override - public Logger getLoggerInstance(String category) { + public Logger getLoggerInstance(@NotNull String category) { return new Log4jBasedLogger(org.apache.log4j.Logger.getLogger(category)); } } diff --git a/jps/standalone-builder/src/org/jetbrains/jps/gant/JpsGantProjectBuilder.java b/jps/standalone-builder/src/org/jetbrains/jps/gant/JpsGantProjectBuilder.java index ee10ff2116c6..8480799b8c1b 100644 --- a/jps/standalone-builder/src/org/jetbrains/jps/gant/JpsGantProjectBuilder.java +++ b/jps/standalone-builder/src/org/jetbrains/jps/gant/JpsGantProjectBuilder.java @@ -406,8 +406,9 @@ public class JpsGantProjectBuilder { private static AntMessageHandler ourMessageHandler; private static Logger.Factory ourFileLoggerFactory; + @NotNull @Override - public Logger getLoggerInstance(String category) { + public Logger getLoggerInstance(@NotNull String category) { DefaultLogger antLogger = new DefaultLogger(category) { @Override public void error(@NonNls String message, @Nullable Throwable t, @NotNull @NonNls String... details) { diff --git a/jps/standalone-builder/src/org/jetbrains/jps/gant/Log4jFileLoggerFactory.java b/jps/standalone-builder/src/org/jetbrains/jps/gant/Log4jFileLoggerFactory.java index b008df8805e8..c5c5fde10162 100644 --- a/jps/standalone-builder/src/org/jetbrains/jps/gant/Log4jFileLoggerFactory.java +++ b/jps/standalone-builder/src/org/jetbrains/jps/gant/Log4jFileLoggerFactory.java @@ -20,6 +20,7 @@ import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.apache.log4j.PatternLayout; import org.apache.log4j.RollingFileAppender; +import org.jetbrains.annotations.NotNull; import java.io.File; import java.io.IOException; @@ -42,8 +43,9 @@ public class Log4jFileLoggerFactory implements com.intellij.openapi.diagnostic.L myAppender.setMaxBackupIndex(10); } + @NotNull @Override - public com.intellij.openapi.diagnostic.Logger getLoggerInstance(String category) { + public com.intellij.openapi.diagnostic.Logger getLoggerInstance(@NotNull String category) { final Logger logger = Logger.getLogger(category); logger.addAppender(myAppender); logger.setLevel(isDebugLevel(category) ? Level.DEBUG : Level.INFO); diff --git a/platform/platform-impl/src/com/intellij/idea/LoggerFactory.java b/platform/platform-impl/src/com/intellij/idea/LoggerFactory.java index ff0b7d134ef4..5a87fb0e1e29 100644 --- a/platform/platform-impl/src/com/intellij/idea/LoggerFactory.java +++ b/platform/platform-impl/src/com/intellij/idea/LoggerFactory.java @@ -21,6 +21,7 @@ import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import org.apache.log4j.LogManager; import org.apache.log4j.xml.DOMConfigurator; +import org.jetbrains.annotations.NotNull; import java.io.File; import java.io.StringReader; @@ -35,8 +36,9 @@ public class LoggerFactory implements Logger.Factory { private LoggerFactory() { } + @NotNull @Override - public synchronized Logger getLoggerInstance(String name) { + public synchronized Logger getLoggerInstance(@NotNull String name) { try { if (!myInitialized) { init(); diff --git a/platform/testFramework/src/com/intellij/testFramework/TestLoggerFactory.java b/platform/testFramework/src/com/intellij/testFramework/TestLoggerFactory.java index 02269aecb88f..eda347a24b86 100644 --- a/platform/testFramework/src/com/intellij/testFramework/TestLoggerFactory.java +++ b/platform/testFramework/src/com/intellij/testFramework/TestLoggerFactory.java @@ -46,8 +46,9 @@ public class TestLoggerFactory implements Logger.Factory { private TestLoggerFactory() { } + @NotNull @Override - public synchronized Logger getLoggerInstance(final String name) { + public synchronized Logger getLoggerInstance(@NotNull final String name) { if (!myInitialized) { init(); } diff --git a/platform/util/src/com/intellij/openapi/diagnostic/Log4jBasedLogger.java b/platform/util/src/com/intellij/openapi/diagnostic/Log4jBasedLogger.java index f33202d869b5..37a8eadf6a17 100644 --- a/platform/util/src/com/intellij/openapi/diagnostic/Log4jBasedLogger.java +++ b/platform/util/src/com/intellij/openapi/diagnostic/Log4jBasedLogger.java @@ -27,7 +27,7 @@ import org.jetbrains.annotations.Nullable; public class Log4jBasedLogger extends Logger { protected final org.apache.log4j.Logger myLogger; - public Log4jBasedLogger(org.apache.log4j.Logger delegate) { + public Log4jBasedLogger(@NotNull org.apache.log4j.Logger delegate) { myLogger = delegate; } From bd19d02fa3a2f8a9626ab56b000157f749b8a1b2 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Mon, 4 Jul 2016 18:33:46 +0300 Subject: [PATCH 10/21] cleanup --- .../daemon/impl/LineMarkersPass.java | 51 +++++++------------ .../daemon/impl/LineMarkersProcessor.java | 1 + 2 files changed, 20 insertions(+), 32 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LineMarkersPass.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LineMarkersPass.java index 8f5ab1982ab5..dd6ecc5b933d 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LineMarkersPass.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LineMarkersPass.java @@ -42,14 +42,11 @@ import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.IndexNotReadyException; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; import com.intellij.psi.impl.source.tree.injected.InjectedLanguageManagerImpl; import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil; -import com.intellij.util.Function; import com.intellij.util.FunctionUtil; -import com.intellij.util.Processor; import com.intellij.util.containers.ContainerUtil; import gnu.trove.THashSet; import gnu.trove.TIntObjectHashMap; @@ -97,7 +94,7 @@ public class LineMarkersPass extends TextEditorHighlightingPass implements LineM @Override public void doCollectInformation(@NotNull ProgressIndicator progress) { - final List lineMarkers = new ArrayList(); + final List lineMarkers = new ArrayList<>(); final FileViewProvider viewProvider = myFile.getViewProvider(); final Set relevantLanguages = viewProvider.getLanguages(); for (Language language : relevantLanguages) { @@ -116,7 +113,7 @@ public class LineMarkersPass extends TextEditorHighlightingPass implements LineM } static List mergeLineMarkers(@NotNull List markers, @Nullable Editor editor) { - List forMerge = new ArrayList(); + List forMerge = new ArrayList<>(); final Iterator iterator = markers.iterator(); while (iterator.hasNext()) { final LineMarkerInfo marker = iterator.next(); @@ -129,13 +126,13 @@ public class LineMarkersPass extends TextEditorHighlightingPass implements LineM if (forMerge.isEmpty() || editor == null) return markers; - final List result = new ArrayList(markers); - TIntObjectHashMap> sameLineMarkers = new TIntObjectHashMap>(); + final List result = new ArrayList<>(markers); + TIntObjectHashMap> sameLineMarkers = new TIntObjectHashMap<>(); for (MergeableLineMarkerInfo info : forMerge) { int line = editor.getDocument().getLineNumber(info.startOffset); List infos = sameLineMarkers.get(line); if (infos == null) { - infos = new ArrayList(); + infos = new ArrayList<>(); sameLineMarkers.put(line, infos); } infos.add(info); @@ -153,10 +150,7 @@ public class LineMarkersPass extends TextEditorHighlightingPass implements LineM List forLanguage = LineMarkerProviders.INSTANCE.allForLanguageOrAny(language); List providers = DumbService.getInstance(project).filterByDumbAwareness(forLanguage); final LineMarkerSettings settings = LineMarkerSettings.getSettings(); - return ContainerUtil.filter(providers, provider -> { - if (!(provider instanceof LineMarkerProviderDescriptor)) return true; - return settings.isEnabled((LineMarkerProviderDescriptor)provider); - }); + return ContainerUtil.filter(providers, provider -> !(provider instanceof LineMarkerProviderDescriptor) || settings.isEnabled((LineMarkerProviderDescriptor)provider)); } @Override @@ -177,10 +171,7 @@ public class LineMarkersPass extends TextEditorHighlightingPass implements LineM try { info = provider.getLineMarkerInfo(element); } - catch (ProcessCanceledException e) { - throw e; - } - catch (IndexNotReadyException e) { + catch (ProcessCanceledException | IndexNotReadyException e) { throw e; } catch (Exception e) { @@ -200,19 +191,14 @@ public class LineMarkersPass extends TextEditorHighlightingPass implements LineM @NotNull final PsiFile file, @NotNull final ProgressIndicator progress) { final InjectedLanguageManager manager = InjectedLanguageManager.getInstance(file.getProject()); - final List injectedMarkers = new ArrayList(); - final Set injectedFiles = new THashSet(); - final PsiLanguageInjectionHost.InjectedPsiVisitor collectingVisitor = new PsiLanguageInjectionHost.InjectedPsiVisitor() { - @Override - public void visit(@NotNull final PsiFile injectedPsi, @NotNull List places) { - injectedFiles.add(injectedPsi); - } - }; + final Set injectedFiles = new THashSet<>(); + final PsiLanguageInjectionHost.InjectedPsiVisitor collectingVisitor = (injectedPsi, places) -> injectedFiles.add(injectedPsi); InjectedLanguageManagerImpl.getInstanceImpl(file.getProject()).processInjectableElements(elements, element -> { InjectedLanguageUtil.enumerate(element, file, false, collectingVisitor); return true; }); + final List injectedMarkers = new ArrayList<>(); for (PsiFile injectedPsi : injectedFiles) { final Project project = injectedPsi.getProject(); Document document = PsiDocumentManager.getInstance(project).getCachedDocument(injectedPsi); @@ -228,8 +214,9 @@ public class LineMarkersPass extends TextEditorHighlightingPass implements LineM TextRange hostRange = manager.injectedToHost(injectedPsi, editable); Icon icon = gutterRenderer == null ? null : gutterRenderer.getIcon(); LineMarkerInfo converted = - new LineMarkerInfo(injectedMarker.getElement(), hostRange, icon, injectedMarker.updatePass, - element -> injectedMarker.getLineMarkerTooltip(), injectedMarker.getNavigationHandler(), GutterIconRenderer.Alignment.RIGHT); + new LineMarkerInfo<>(injectedMarker.getElement(), hostRange, icon, injectedMarker.updatePass, + element -> injectedMarker.getLineMarkerTooltip(), injectedMarker.getNavigationHandler(), + GutterIconRenderer.Alignment.RIGHT); result.add(converted); } } @@ -250,13 +237,13 @@ public class LineMarkersPass extends TextEditorHighlightingPass implements LineM @NotNull public static LineMarkerInfo createMethodSeparatorLineMarker(@NotNull PsiElement startFrom, @NotNull EditorColorsManager colorsManager) { - LineMarkerInfo info = new LineMarkerInfo( - startFrom, - startFrom.getTextRange(), - null, - Pass.UPDATE_ALL, + LineMarkerInfo info = new LineMarkerInfo<>( + startFrom, + startFrom.getTextRange(), + null, + Pass.UPDATE_ALL, FunctionUtil.nullConstant(), - null, + null, GutterIconRenderer.Alignment.RIGHT ); EditorColorsScheme scheme = colorsManager.getGlobalScheme(); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LineMarkersProcessor.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LineMarkersProcessor.java index 71f58d029628..55bb373a3c6b 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LineMarkersProcessor.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LineMarkersProcessor.java @@ -28,6 +28,7 @@ import java.util.List; /** * @author cdr */ +@FunctionalInterface interface LineMarkersProcessor { void addLineMarkers(@NotNull List elements, @NotNull List providers, From 1c24907166b1b760599f2174792b32e74bd41821 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Mon, 4 Jul 2016 18:35:25 +0300 Subject: [PATCH 11/21] cleanup --- .../intellij/codeInsight/daemon/impl/LineMarkersPass.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LineMarkersPass.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LineMarkersPass.java index dd6ecc5b933d..762df47b9808 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LineMarkersPass.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LineMarkersPass.java @@ -112,6 +112,7 @@ public class LineMarkersPass extends TextEditorHighlightingPass implements LineM myMarkers = mergeLineMarkers(lineMarkers, myEditor); } + @NotNull static List mergeLineMarkers(@NotNull List markers, @Nullable Editor editor) { List forMerge = new ArrayList<>(); final Iterator iterator = markers.iterator(); @@ -126,7 +127,7 @@ public class LineMarkersPass extends TextEditorHighlightingPass implements LineM if (forMerge.isEmpty() || editor == null) return markers; - final List result = new ArrayList<>(markers); + List result = new ArrayList<>(markers); TIntObjectHashMap> sameLineMarkers = new TIntObjectHashMap<>(); for (MergeableLineMarkerInfo info : forMerge) { int line = editor.getDocument().getLineNumber(info.startOffset); @@ -146,11 +147,13 @@ public class LineMarkersPass extends TextEditorHighlightingPass implements LineM return result; } + @NotNull public static List getMarkerProviders(@NotNull Language language, @NotNull final Project project) { List forLanguage = LineMarkerProviders.INSTANCE.allForLanguageOrAny(language); List providers = DumbService.getInstance(project).filterByDumbAwareness(forLanguage); final LineMarkerSettings settings = LineMarkerSettings.getSettings(); - return ContainerUtil.filter(providers, provider -> !(provider instanceof LineMarkerProviderDescriptor) || settings.isEnabled((LineMarkerProviderDescriptor)provider)); + return ContainerUtil.filter(providers, provider -> !(provider instanceof LineMarkerProviderDescriptor) + || settings.isEnabled((LineMarkerProviderDescriptor)provider)); } @Override From 4a02579a5770eae98f875a1c59364aae7a81edd6 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Mon, 4 Jul 2016 18:47:36 +0300 Subject: [PATCH 12/21] compilation fix --- .../src/com/intellij/psi/impl/DocumentCommitThread.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/core-impl/src/com/intellij/psi/impl/DocumentCommitThread.java b/platform/core-impl/src/com/intellij/psi/impl/DocumentCommitThread.java index e29dee5ed92c..0a069a9ca0c8 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/DocumentCommitThread.java +++ b/platform/core-impl/src/com/intellij/psi/impl/DocumentCommitThread.java @@ -161,7 +161,7 @@ public class DocumentCommitThread implements Runnable, Disposable, DocumentCommi // under lock private void wakeUpQueue() { if (!isDisposed && !documentsToCommit.isEmpty()) { - executor.execute(ProgressManager.getInstance().longProcess("Commit documents", this)); + executor.execute(this); } } From 4b82c441cca207742661ad474889d8d63d006e55 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Mon, 4 Jul 2016 18:56:54 +0300 Subject: [PATCH 13/21] diagnostics for missing line markers --- .../impl/DaemonRespondToChangesTest.java | 38 +++++++++++++------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/impl/DaemonRespondToChangesTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/impl/DaemonRespondToChangesTest.java index f0a8543d72b6..146002378c72 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/impl/DaemonRespondToChangesTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/impl/DaemonRespondToChangesTest.java @@ -848,10 +848,12 @@ public class DaemonRespondToChangesTest extends DaemonAnalyzerTestCase { public void testLineMarkersClearWhenTypingAtTheEndOfPsiComment() throws Throwable { configureByText(JavaFileType.INSTANCE, "class S {\n//ddd\n}"); + StringBuffer log = new StringBuffer(); final LineMarkerProvider provider = new LineMarkerProvider() { @Nullable @Override public LineMarkerInfo getLineMarkerInfo(@NotNull PsiElement element) { + log.append("getLineMarkerInfo(" + element + ")\n"); if (element instanceof PsiComment) { return new LineMarkerInfo<>((PsiComment)element, element.getTextRange(), null, Pass.UPDATE_ALL, null, null, GutterIconRenderer.Alignment.LEFT); @@ -867,22 +869,34 @@ public class DaemonRespondToChangesTest extends DaemonAnalyzerTestCase { LineMarkerProviders.INSTANCE.addExplicitExtension(JavaLanguage.INSTANCE, provider); Disposer.register(myTestRootDisposable, () -> LineMarkerProviders.INSTANCE.removeExplicitExtension(JavaLanguage.INSTANCE, provider)); - assertEmpty(highlightErrors()); + try { + List infos = highlightErrors(); + log.append("infos: " + infos + "\n"); + assertEmpty(infos); - List lineMarkers = DaemonCodeAnalyzerImpl.getLineMarkers(myEditor.getDocument(), getProject()); - assertOneElement(lineMarkers); + List lineMarkers = DaemonCodeAnalyzerImpl.getLineMarkers(myEditor.getDocument(), getProject()); + assertOneElement(lineMarkers); - type(' '); - assertEmpty(highlightErrors()); + type(' '); + infos = highlightErrors(); + log.append("infos: " + infos + "\n"); + assertEmpty(infos); - lineMarkers = DaemonCodeAnalyzerImpl.getLineMarkers(myEditor.getDocument(), getProject()); - assertOneElement(lineMarkers); + lineMarkers = DaemonCodeAnalyzerImpl.getLineMarkers(myEditor.getDocument(), getProject()); + assertOneElement(lineMarkers); - backspace(); - assertEmpty(highlightErrors()); + backspace(); + infos = highlightErrors(); + log.append("infos: " + infos + "\n"); + assertEmpty(infos); - lineMarkers = DaemonCodeAnalyzerImpl.getLineMarkers(myEditor.getDocument(), getProject()); - assertOneElement(lineMarkers); + lineMarkers = DaemonCodeAnalyzerImpl.getLineMarkers(myEditor.getDocument(), getProject()); + assertOneElement(lineMarkers); + } + catch (AssertionError e) { + System.err.println("Log:\n"+log); + throw e; + } } public void testWhenTypingOverWrongReferenceItsColorChangesToBlackAndOnlyAfterHighlightingFinishedItReturnsToRed() throws Throwable { @@ -1533,7 +1547,6 @@ public class DaemonRespondToChangesTest extends DaemonAnalyzerTestCase { } public void testReactivityPerformance() throws Throwable { - List watchers = new ArrayList<>(); @NonNls String filePath = "/psi/resolve/Thinlet.java"; configureByFile(filePath); type(' '); @@ -1547,6 +1560,7 @@ public class DaemonRespondToChangesTest extends DaemonAnalyzerTestCase { int N = Math.max(5, Timings.adjustAccordingToMySpeed(80, true)); System.out.println("N = " + N); final long[] interruptTimes = new long[N]; + List watchers = new ArrayList<>(); for (int i = 0; i < N; i++) { codeAnalyzer.restart(); final int finalI = i; From 87dd5b71434e59b803f8533ec35e799e7d88c9c3 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Tue, 5 Jul 2016 14:23:55 +0300 Subject: [PATCH 14/21] cleanup --- .../src/com/intellij/idea/IdeaLogger.java | 33 +++++++++---------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/idea/IdeaLogger.java b/platform/platform-impl/src/com/intellij/idea/IdeaLogger.java index 75e159663e66..cbc22c5f149e 100644 --- a/platform/platform-impl/src/com/intellij/idea/IdeaLogger.java +++ b/platform/platform-impl/src/com/intellij/idea/IdeaLogger.java @@ -40,7 +40,7 @@ import java.io.LineNumberReader; /** * @author Mike */ -@SuppressWarnings({"HardCodedStringLiteral"}) +@SuppressWarnings("HardCodedStringLiteral") public class IdeaLogger extends Log4jBasedLogger { private static ApplicationInfoProvider ourApplicationInfoProvider = getIdeaInfoProvider(); @@ -53,11 +53,11 @@ public class IdeaLogger extends Log4jBasedLogger { return ourCompilationTimestamp; } - private static String ourCompilationTimestamp; + private static final String ourCompilationTimestamp; @NonNls private static final String COMPILATION_TIMESTAMP_RESOURCE_NAME = "/.compilation-timestamp"; - private static ThrowableRenderer ourThrowableRenderer = t -> { + private static final ThrowableRenderer ourThrowableRenderer = t -> { String[] defaultRes = DefaultThrowableRenderer.render(t); int maxStackSize = 1024; int maxExtraSize = 256; @@ -73,24 +73,22 @@ public class IdeaLogger extends Log4jBasedLogger { static { InputStream stream = Logger.class.getResourceAsStream(COMPILATION_TIMESTAMP_RESOURCE_NAME); + String stamp = null; if (stream != null) { try { - LineNumberReader reader = new LineNumberReader(new InputStreamReader(stream)); - try { + try (LineNumberReader reader = new LineNumberReader(new InputStreamReader(stream))) { String s = reader.readLine(); if (s != null) { - ourCompilationTimestamp = s.trim(); + stamp = s.trim(); } } - finally { - reader.close(); - } } catch (IOException ignored) { } } + ourCompilationTimestamp = stamp; } - IdeaLogger(org.apache.log4j.Logger logger) { + IdeaLogger(@NotNull org.apache.log4j.Logger logger) { super(logger); LoggerRepository repository = myLogger.getLoggerRepository(); if (repository instanceof ThrowableRendererSupport) { @@ -109,7 +107,7 @@ public class IdeaLogger extends Log4jBasedLogger { } @Override - public void error(@NonNls String message, Attachment... attachments) { + public void error(@NonNls String message, @NotNull Attachment... attachments) { myLogger.error(LogMessageEx.createEvent(message, DebugUtil.currentStackTrace(), attachments)); } @@ -170,21 +168,20 @@ public class IdeaLogger extends Log4jBasedLogger { } } + @NotNull public static ThrowableRenderer getThrowableRenderer() { return ourThrowableRenderer; } - public static void setApplicationInfoProvider(ApplicationInfoProvider aProvider) { + public static void setApplicationInfoProvider(@NotNull ApplicationInfoProvider aProvider) { ourApplicationInfoProvider = aProvider; } + @NotNull private static ApplicationInfoProvider getIdeaInfoProvider() { - return new ApplicationInfoProvider() { - @Override - public String getInfo() { - final ApplicationInfoEx info = ApplicationInfoImpl.getShadowInstance(); - return info.getFullApplicationName() + " " + "Build #" + info.getBuild().asString(); - } + return () -> { + final ApplicationInfoEx info = ApplicationInfoImpl.getShadowInstance(); + return info.getFullApplicationName() + " " + "Build #" + info.getBuild().asString(); }; } } From 88b49fba0ea8249a4842e28623e5095509ec8767 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Tue, 5 Jul 2016 14:24:31 +0300 Subject: [PATCH 15/21] do not ignore attachments by default in Teamcity --- .../openapi/diagnostic/DefaultLogger.java | 12 +------ .../intellij/openapi/diagnostic/Logger.java | 32 +++++++++++++------ 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/platform/util/src/com/intellij/openapi/diagnostic/DefaultLogger.java b/platform/util/src/com/intellij/openapi/diagnostic/DefaultLogger.java index 0943a0775ae1..ba7470cb3494 100644 --- a/platform/util/src/com/intellij/openapi/diagnostic/DefaultLogger.java +++ b/platform/util/src/com/intellij/openapi/diagnostic/DefaultLogger.java @@ -17,7 +17,6 @@ package com.intellij.openapi.diagnostic; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.ExceptionUtil; -import com.intellij.util.Function; import org.apache.log4j.Level; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -81,17 +80,8 @@ public class DefaultLogger extends Logger { //noinspection ThrowableResultOfMethodCallIgnored Throwable rootCause = t == null ? null : ExceptionUtil.getRootCause(t); if (rootCause instanceof ExceptionWithAttachments) { - return "\nAttachments:" + StringUtil.join(((ExceptionWithAttachments)rootCause).getAttachments(), - new Function() { - @Override - public String fun(Attachment attachment) { - return attachment.getPath() + "\n" + attachment.getDisplayText(); - } - }, - "\n----\n"); + return "\nAttachments:" + StringUtil.join(((ExceptionWithAttachments)rootCause).getAttachments(), ATTACHMENT_TO_STRING, "\n----\n"); } return ""; } - - } diff --git a/platform/util/src/com/intellij/openapi/diagnostic/Logger.java b/platform/util/src/com/intellij/openapi/diagnostic/Logger.java index dae2659cd16c..03ebe3270941 100644 --- a/platform/util/src/com/intellij/openapi/diagnostic/Logger.java +++ b/platform/util/src/com/intellij/openapi/diagnostic/Logger.java @@ -17,6 +17,8 @@ package com.intellij.openapi.diagnostic; import com.intellij.util.ArrayUtil; import com.intellij.util.ExceptionUtil; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; import org.apache.log4j.Level; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NonNls; @@ -27,19 +29,21 @@ import java.lang.reflect.Constructor; public abstract class Logger { public interface Factory { - Logger getLoggerInstance(String category); + @NotNull + Logger getLoggerInstance(@NotNull String category); } private static class DefaultFactory implements Factory { + @NotNull @Override - public Logger getLoggerInstance(String category) { + public Logger getLoggerInstance(@NotNull String category) { return new DefaultLogger(category); } } private static Factory ourFactory = new DefaultFactory(); - public static void setFactory(Class factory) { + public static void setFactory(@NotNull Class factory) { if (isInitialized()) { if (factory.isInstance(ourFactory)) { return; @@ -65,12 +69,13 @@ public abstract class Logger { return !(ourFactory instanceof DefaultFactory); } - public static Logger getInstance(@NonNls String category) { + @NotNull + public static Logger getInstance(@NotNull @NonNls String category) { return ourFactory.getLoggerInstance(category); } @NotNull - public static Logger getInstance(Class cl) { + public static Logger getInstance(@NotNull Class cl) { return getInstance("#" + cl.getName()); } @@ -82,12 +87,12 @@ public abstract class Logger { public abstract void debug(@NonNls String message, @Nullable Throwable t); - public void debug(@NotNull String message, Object... details) { + public void debug(@NotNull String message, @NotNull Object... details) { if (isDebugEnabled()) { StringBuilder sb = new StringBuilder(); sb.append(message); for (Object detail : details) { - sb.append(String.valueOf(detail)); + sb.append(detail); } debug(sb.toString()); } @@ -130,11 +135,18 @@ public abstract class Logger { error(String.valueOf(message)); } - public void error(@NonNls String message, Attachment... attachments) { - error(message); + static final Function ATTACHMENT_TO_STRING = new Function() { + @Override + public String fun(Attachment attachment) { + return attachment.getPath() + "\n" + attachment.getDisplayText(); + } + }; + + public void error(@NonNls String message, @NotNull Attachment... attachments) { + error(message, null, ContainerUtil.map2Array(attachments, String.class, ATTACHMENT_TO_STRING)); } - public void error(@NonNls String message, @NonNls String... details) { + public void error(@NonNls String message, @NonNls @NotNull String... details) { error(message, new Throwable(), details); } From 143bb270fe5e732fd7ea7e099e07dd0d749d1213 Mon Sep 17 00:00:00 2001 From: irengrig Date: Tue, 5 Jul 2016 13:33:59 +0200 Subject: [PATCH 16/21] IDEA-158107 JsonSchemaFileTypeManager leaks project after closing --- .../com/jetbrains/jsonSchema/JsonSchemaFileTypeManager.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/json/src/com/jetbrains/jsonSchema/JsonSchemaFileTypeManager.java b/json/src/com/jetbrains/jsonSchema/JsonSchemaFileTypeManager.java index 45fd1c74fffc..a5b7f9471623 100644 --- a/json/src/com/jetbrains/jsonSchema/JsonSchemaFileTypeManager.java +++ b/json/src/com/jetbrains/jsonSchema/JsonSchemaFileTypeManager.java @@ -41,6 +41,10 @@ public class JsonSchemaFileTypeManager implements ProjectManagerListener { return ServiceManager.getService(JsonSchemaFileTypeManager.class); } + public JsonSchemaFileTypeManager() { + ProjectManager.getInstance().addProjectManagerListener(this); + } + public boolean isJsonSchemaFile(@NotNull final VirtualFile file) { ensureInitialized(); for (Collection files : myFileSets.values()) { From 8b5db93a5bdea028c79873fa3a937f0920fd31f8 Mon Sep 17 00:00:00 2001 From: Anton Makeev Date: Tue, 5 Jul 2016 13:49:52 +0200 Subject: [PATCH 17/21] ProjectRootUtil.findSymlinkedFileInContent handles situation when s link to a file outside of the project root it passed. context: CPP-7052 General support for project opened from symlinked directories, including remote debug and path mappings --- .../openapi/roots/ProjectRootUtil.java | 7 +- .../ProjectRootUtilSymlinkedFilesTest.java | 75 ++++++++++++------- 2 files changed, 52 insertions(+), 30 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/roots/ProjectRootUtil.java b/platform/platform-impl/src/com/intellij/openapi/roots/ProjectRootUtil.java index 15017802c552..71e83505ac0d 100644 --- a/platform/platform-impl/src/com/intellij/openapi/roots/ProjectRootUtil.java +++ b/platform/platform-impl/src/com/intellij/openapi/roots/ProjectRootUtil.java @@ -30,11 +30,14 @@ public class ProjectRootUtil { if (scope.contains(forFile)) return forFile; + VirtualFile canonicalForFile = forFile.getCanonicalFile(); + if (canonicalForFile == null) canonicalForFile = forFile; + Collection projectFiles = - FilenameIndex.getVirtualFilesByName(project, forFile.getName(), true, scope); + FilenameIndex.getVirtualFilesByName(project, canonicalForFile.getName(), true, scope); for (VirtualFile eachContentFile : projectFiles) { - if (forFile.equals(eachContentFile.getCanonicalFile())) return eachContentFile; + if (canonicalForFile.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 index 54cf9bdfea8e..be8d8418f828 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/roots/ProjectRootUtilSymlinkedFilesTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/roots/ProjectRootUtilSymlinkedFilesTest.java @@ -30,9 +30,10 @@ import java.io.File; import java.io.IOException; public class ProjectRootUtilSymlinkedFilesTest extends PlatformTestCase { - private File myCanonicalDir; - private File myCanonicalFile; - private VirtualFile myCanonicalVFile; + private File myNonContentDir; + private File myNonContentFile; + private VirtualFile myNonContentVFile; + private File myContentDir; private VirtualFile myContentVDir; private File myLibraryDir; @@ -46,12 +47,12 @@ public class ProjectRootUtilSymlinkedFilesTest extends PlatformTestCase { @Override public void setUp() throws Exception { super.setUp(); - myCanonicalDir = FileUtil.createTempDirectory("canonical", null); - myCanonicalFile = new File(myCanonicalDir, "foo.txt"); - assertTrue(myCanonicalFile.createNewFile()); + myNonContentDir = FileUtil.createTempDirectory("nonContent", null); + myNonContentFile = new File(myNonContentDir, "foo.txt"); + assertTrue(myNonContentFile.createNewFile()); - myCanonicalVFile = VfsUtil.findFileByIoFile(myCanonicalFile, true); - assertNotNull(myCanonicalVFile); + myNonContentVFile = VfsUtil.findFileByIoFile(myNonContentFile, true); + assertNotNull(myNonContentVFile); myContentDir = FileUtil.createTempDirectory("content", null); myContentVDir = VfsUtil.findFileByIoFile(myContentDir, true); @@ -65,7 +66,7 @@ public class ProjectRootUtilSymlinkedFilesTest extends PlatformTestCase { } public void testNoFilesInContent() throws Exception { - assertEquals(myCanonicalVFile, ProjectRootUtil.findSymlinkedFileInContent(getProject(), myCanonicalVFile)); + assertEquals(myNonContentVFile, ProjectRootUtil.findSymlinkedFileInContent(getProject(), myNonContentVFile)); } public void testLinkedDirInContent() throws Exception { @@ -78,48 +79,48 @@ public class ProjectRootUtilSymlinkedFilesTest extends PlatformTestCase { public void doTestLinkedDirInProjectRoots(boolean content) throws Exception { String linkedPath = (content ? myContentDir : myLibraryDir).getPath() + "/linked"; - IoTestUtil.createSymLink(myCanonicalDir.getPath(), linkedPath, true); + IoTestUtil.createSymLink(myNonContentDir.getPath(), linkedPath, true); - VirtualFile linkedVFile = VfsUtil.findFileByIoFile(new File(linkedPath, myCanonicalFile.getName()), true); + VirtualFile linkedVFile = VfsUtil.findFileByIoFile(new File(linkedPath, myNonContentFile.getName()), true); - assertEquals(linkedVFile, ProjectRootUtil.findSymlinkedFileInContent(getProject(), myCanonicalVFile)); + assertEquals(linkedVFile, ProjectRootUtil.findSymlinkedFileInContent(getProject(), myNonContentVFile)); } // not supported public void _testLinkedFileInSources() throws Exception { String linkedPath = myContentDir.getPath() + "/linked.txt"; - IoTestUtil.createSymLink(myCanonicalVFile.getPath(), linkedPath, true); + IoTestUtil.createSymLink(myNonContentVFile.getPath(), linkedPath, true); VirtualFile linkedVFile = VfsUtil.findFileByIoFile(new File(linkedPath), true); - assertEquals(linkedVFile, ProjectRootUtil.findSymlinkedFileInContent(getProject(), myCanonicalVFile)); + assertEquals(linkedVFile, ProjectRootUtil.findSymlinkedFileInContent(getProject(), myNonContentVFile)); } public void testFileWithTheSameNotButNotLinked() throws Exception { new WriteAction() { @Override protected void run(@NotNull Result result) throws Throwable { - myContentVDir.createChildData(this, myCanonicalFile.getName()); + myContentVDir.createChildData(this, myNonContentFile.getName()); } }.execute(); - assertEquals(myCanonicalVFile, ProjectRootUtil.findSymlinkedFileInContent(getProject(), myCanonicalVFile)); + assertEquals(myNonContentVFile, ProjectRootUtil.findSymlinkedFileInContent(getProject(), myNonContentVFile)); } 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); + IoTestUtil.createSymLink(myNonContentDir.getPath(), linkedPath1, true); + VirtualFile linkedVFile1 = VfsUtil.findFileByIoFile(new File(linkedPath1, myNonContentFile.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); + IoTestUtil.createSymLink(myNonContentDir.getPath(), linkedPath2, true); + VirtualFile linkedVFile2 = VfsUtil.findFileByIoFile(new File(linkedPath2, myNonContentFile.getName()), true); assertNotNull(linkedVFile2); - VirtualFile found = ProjectRootUtil.findSymlinkedFileInContent(getProject(), myCanonicalVFile); + VirtualFile found = ProjectRootUtil.findSymlinkedFileInContent(getProject(), myNonContentVFile); assertTrue(found.equals(linkedVFile1) || found.equals(linkedVFile2)); for(int i = 0; i < 10; i++) { - assertEquals("try: " + i, found, ProjectRootUtil.findSymlinkedFileInContent(getProject(), myCanonicalVFile)); + assertEquals("try: " + i, found, ProjectRootUtil.findSymlinkedFileInContent(getProject(), myNonContentVFile)); } } @@ -133,15 +134,33 @@ public class ProjectRootUtilSymlinkedFilesTest extends PlatformTestCase { private void doTestLinkedAndCanonicalUnderRoot(boolean content) throws InterruptedException, IOException { String linkedPath = myContentDir.getPath() + "/linked"; - IoTestUtil.createSymLink(myCanonicalDir.getPath(), linkedPath, true); + IoTestUtil.createSymLink(myNonContentDir.getPath(), linkedPath, true); - VirtualFile linkedVFile = VfsUtil.findFileByIoFile(new File(linkedPath, myCanonicalFile.getName()), true); - assertEquals(linkedVFile, ProjectRootUtil.findSymlinkedFileInContent(getProject(), myCanonicalVFile)); + VirtualFile linkedVFile = VfsUtil.findFileByIoFile(new File(linkedPath, myNonContentFile.getName()), true); + assertEquals(linkedVFile, ProjectRootUtil.findSymlinkedFileInContent(getProject(), myNonContentVFile)); if(content) { - PsiTestUtil.addContentRoot(getModule(), myCanonicalVFile.getParent()); + PsiTestUtil.addContentRoot(getModule(), myNonContentVFile.getParent()); } else { - PsiTestUtil.addLibrary(getModule(), myCanonicalVFile.getParent().getPath()); + PsiTestUtil.addLibrary(getModule(), myNonContentVFile.getParent().getPath()); } - assertEquals(myCanonicalVFile, ProjectRootUtil.findSymlinkedFileInContent(getProject(), myCanonicalVFile)); + assertEquals(myNonContentVFile, ProjectRootUtil.findSymlinkedFileInContent(getProject(), myNonContentVFile)); + } + + public void testLinkedFileNotUnderTheContentRoot() throws Exception { + File nonContentDir = FileUtil.createTempDirectory("nonContent2", null); + String nonContentLinkedPath = nonContentDir + "/linked"; + + IoTestUtil.createSymLink(myNonContentDir.getPath(), nonContentLinkedPath, true); + VirtualFile nonContentLinkedVFile = VfsUtil.findFileByIoFile(new File(nonContentLinkedPath, myNonContentFile.getName()), true); + + assertEquals(nonContentLinkedVFile, ProjectRootUtil.findSymlinkedFileInContent(getProject(), nonContentLinkedVFile)); + + String contentLinkedPath = myContentDir + "/linked"; + IoTestUtil.createSymLink(myNonContentDir.getPath(), contentLinkedPath, true); + VirtualFile contentLinkedVFile = VfsUtil.findFileByIoFile(new File(contentLinkedPath, myNonContentFile.getName()), true); + + assertEquals(contentLinkedVFile, ProjectRootUtil.findSymlinkedFileInContent(getProject(), myNonContentVFile)); + assertEquals(contentLinkedVFile, ProjectRootUtil.findSymlinkedFileInContent(getProject(), nonContentLinkedVFile)); + assertEquals(contentLinkedVFile, ProjectRootUtil.findSymlinkedFileInContent(getProject(), contentLinkedVFile)); } } From a289888a1d3c6b67c4ec2410c42b527f7e901bc6 Mon Sep 17 00:00:00 2001 From: Dmitry Batrak Date: Tue, 5 Jul 2016 14:52:11 +0300 Subject: [PATCH 18/21] Soft-wrap toggling popup button doesn't work in breakpoint's editor preview --- .../com/intellij/ui/popup/util/DetailViewImpl.java | 14 ++++++++++---- .../openapi/editor/impl/EditorComponentImpl.java | 3 +-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ui/popup/util/DetailViewImpl.java b/platform/lang-impl/src/com/intellij/ui/popup/util/DetailViewImpl.java index e2e2ad06d014..25cd9eaebeeb 100644 --- a/platform/lang-impl/src/com/intellij/ui/popup/util/DetailViewImpl.java +++ b/platform/lang-impl/src/com/intellij/ui/popup/util/DetailViewImpl.java @@ -21,6 +21,8 @@ import com.intellij.openapi.editor.colors.EditorColorsScheme; import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.editor.highlighter.EditorHighlighter; import com.intellij.openapi.editor.highlighter.EditorHighlighterFactory; +import com.intellij.openapi.editor.impl.SettingsImpl; +import com.intellij.openapi.editor.impl.softwrap.SoftWrapAppliancePlaces; import com.intellij.openapi.editor.markup.HighlighterLayer; import com.intellij.openapi.editor.markup.RangeHighlighter; import com.intellij.openapi.editor.markup.TextAttributes; @@ -136,10 +138,14 @@ public class DetailViewImpl extends JPanel implements DetailView, UserDataHolder ((EditorEx)getEditor()).setFile(file); ((EditorEx)getEditor()).setHighlighter(highlighter); - getEditor().getSettings().setAnimatedScrolling(false); - getEditor().getSettings().setRefrainFromScrolling(false); - getEditor().getSettings().setLineNumbersShown(true); - getEditor().getSettings().setFoldingOutlineShown(false); + EditorSettings settings = getEditor().getSettings(); + settings.setAnimatedScrolling(false); + settings.setRefrainFromScrolling(false); + settings.setLineNumbersShown(true); + settings.setFoldingOutlineShown(false); + if (settings instanceof SettingsImpl) { + ((SettingsImpl)settings).setSoftWrapAppliancePlace(SoftWrapAppliancePlaces.PREVIEW); + } ((EditorEx)getEditor()).getFoldingModel().setFoldingEnabled(false); add(getEditor().getComponent(), BorderLayout.CENTER); diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorComponentImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorComponentImpl.java index e18f6b46db7a..dd45f0cf3527 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorComponentImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorComponentImpl.java @@ -130,8 +130,7 @@ public class EditorComponentImpl extends JTextComponent implements Scrollable, D if (myEditor.isDisposed() || myEditor.isRendererMode()) return null; if (CommonDataKeys.EDITOR.is(dataId)) { - // for 'big' editors return null to allow injected editors (see com.intellij.openapi.fileEditor.impl.text.TextEditorComponent.getData()) - return myEditor.getVirtualFile() == null ? myEditor : null; + return myEditor; } if (CommonDataKeys.CARET.is(dataId)) { return myEditor.getCaretModel().getCurrentCaret(); From daeedb475fe5fc080d489834917fb6430c22b8e4 Mon Sep 17 00:00:00 2001 From: "Ilya.Kazakevich" Date: Tue, 5 Jul 2016 01:20:09 +0300 Subject: [PATCH 19/21] Add environments to PATH to make them discoverable by tox Gradle now creates links for pythons: python -> python2.7 Tox may use this info to find correct interpreter, but envs need to be added to PATH This branch depends on https://github.com/throwable-one/gradle-python-envs/commit/81bcdcbdce2361acb69e4fd156a626db730f4746 --- python/setup-test-environment/build.gradle | 14 +++++++------- python/testSrc/com/jetbrains/env/PyToxTest.java | 14 ++++++++++++++ 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/python/setup-test-environment/build.gradle b/python/setup-test-environment/build.gradle index 74dde899cdce..e275e9ae1726 100644 --- a/python/setup-test-environment/build.gradle +++ b/python/setup-test-environment/build.gradle @@ -1,7 +1,7 @@ import org.apache.tools.ant.taskdefs.condition.Os plugins { - id "com.jetbrains.python.envs" version "0.0.6" + id "com.jetbrains.python.envs" version "0.0.7" } @@ -12,16 +12,16 @@ envs { packages = ["pip", "setuptools"] _64Bits = true - conda "django19", "2.7", ["django==1.9", "tox", "nose", "pytest", "behave", "lettuce>=0.2.22"] + conda "django19", "2.7", ["django==1.9", "tox", "nose", "pytest", "behave", "lettuce>=0.2.22"], true textfile "django19/tags.txt", "django\nnose\npytest\nbehave\nlettuce\npackaging\ntox" - conda "django18", "2.7", ["django==1.6"] + conda "django18", "2.7", ["django==1.6"], false textfile "django18/tags.txt", "django" - conda "django17", "2.7", ["django==1.7"] + conda "django17", "2.7", ["django==1.7"], false textfile "django17/tags.txt", "django\nskeletons" - - conda "python34", "3.4", ["ipython==2.1", "django==1.6", "behave", "jinja2", "tox>=2.0", "pandas"] + + conda "python34", "3.4", ["ipython==2.1", "django==1.6", "behave", "jinja2", "tox>=2.0", "pandas"], true textfile "python34/tags.txt", "python3\nipython\nipython200\nskeletons\ndjango\nbehave\ntox\njinja2\npython34\npackaging\npandas" if (!Os.isFamily(Os.FAMILY_WINDOWS)) { @@ -32,7 +32,7 @@ envs { // textfile "pyqt5/tags.txt", "pyqt5" } - conda "django_latest", "3.5", ["django"] + conda "django_latest", "3.5", ["django"], true textfile "django_latest/tags.txt", "django" } diff --git a/python/testSrc/com/jetbrains/env/PyToxTest.java b/python/testSrc/com/jetbrains/env/PyToxTest.java index 5c4ee346bcb4..ef8873ef665b 100644 --- a/python/testSrc/com/jetbrains/env/PyToxTest.java +++ b/python/testSrc/com/jetbrains/env/PyToxTest.java @@ -20,6 +20,7 @@ import com.intellij.execution.testframework.sm.runner.SMTestProxy; import com.intellij.execution.testframework.sm.runner.ui.MockPrinter; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.text.StringUtil; import com.jetbrains.python.sdkTools.SdkCreationType; import com.jetbrains.python.testing.tox.PyToxConfiguration; import com.jetbrains.python.testing.tox.PyToxConfigurationFactory; @@ -30,6 +31,7 @@ import org.jetbrains.annotations.Nullable; import org.junit.Assert; import org.junit.Test; +import java.io.File; import java.io.IOException; import java.util.*; import java.util.function.Supplier; @@ -362,6 +364,18 @@ public final class PyToxTest extends PyEnvTestCase { private MyTestProcessRunner(final int timesToRerunFailedTests) { super(PyToxConfigurationFactory.INSTANCE, PyToxConfiguration.class, timesToRerunFailedTests); } + + @Override + protected void configurationCreatedAndWillLaunch(@NotNull PyToxConfiguration configuration) throws IOException { + super.configurationCreatedAndWillLaunch(configuration); + + // To help tox with all interpreters, we add all our environments to path + // Envs should have binaries like "python2.7" (with version included), + // and tox will find em: see tox_get_python_executable @ interpreters.py + final String join = StringUtil.join(getPythonRoots(), File.pathSeparator); + configuration.getEnvs().put("PATH", join); + + } } private static final class InterpreterExpectations { From eacf1a859b4d8c9b2dd5419369f1554ca6dbd22e Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Tue, 5 Jul 2016 15:48:26 +0300 Subject: [PATCH 20/21] fixed position for empty border effect to match caret position --- .../intellij/openapi/editor/impl/view/EditorPainter.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/EditorPainter.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/EditorPainter.java index 07332eabc058..1de3624296ea 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/EditorPainter.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/EditorPainter.java @@ -707,11 +707,17 @@ class EditorPainter implements TextDrawingCallback { float startX = ranges.get(i); float endX = ranges.get(i + 1); if (startX == endX) { - endX++; + if (startX > 0) { + startX--; + } + else { + endX++; + } } else { endX--; } + ranges.set(i, startX); ranges.set(i + 1, endX); } return ranges; From 8fc91c65039570af33997f41f9abefc38d078f9b Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 5 Jul 2016 15:10:02 +0200 Subject: [PATCH 21/21] minor stub hierarchy clarification --- .../psi/stubsHierarchy/impl/StubResolver.java | 23 +++++++------------ 1 file changed, 8 insertions(+), 15 deletions(-) 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 5d35b4210bfd..3045dda4787c 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 @@ -15,8 +15,6 @@ */ 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; @@ -48,11 +46,10 @@ public class StubResolver { 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); + selectSym(symbol, shortName, processPackages, result); } if (result.isEmpty()) { throw IncompleteHierarchyException.INSTANCE; @@ -79,30 +76,26 @@ public class StubResolver { for (Symbol s = startScope; s != null; s = s.myOwner) findMemberType(s, name, symbols); // type from current package - findIdentInPackage(startScope.pkg(), name, IndexTree.CLASS, symbols); + findIdentInPackage(startScope.pkg(), name, false, symbols); } // resolving `receiver.name` - private void selectSym(Symbol receiver, @ShortName int name, int kind, Set symbols) throws IncompleteHierarchyException { + private void selectSym(Symbol receiver, @ShortName int name, boolean processPackages, Set symbols) throws IncompleteHierarchyException { if (receiver.isPackage()) - findIdentInPackage((Symbol.PackageSymbol)receiver, name, kind, symbols); + findIdentInPackage((Symbol.PackageSymbol)receiver, name, processPackages, symbols); else findMemberType(receiver, name, symbols); } - private void findIdentInPackage(Symbol.PackageSymbol pck, @ShortName int name, int kind, Set symbols) { + private void findIdentInPackage(Symbol.PackageSymbol pck, @ShortName int name, boolean processPackages, Set symbols) { @QNameId int fullname = mySymbols.myNameEnvironment.findExistingName(pck.myQualifiedName, name); if (fullname < 0) { return; } - if (BitUtil.isSet(kind, IndexTree.PACKAGE)) { - Symbol.PackageSymbol pkg = mySymbols.getPackage(fullname); - if (pkg != null) - symbols.add(pkg); - } - if (BitUtil.isSet(kind, IndexTree.CLASS)) { - Collections.addAll(symbols, findGlobalType(fullname)); + if (processPackages) { + ContainerUtil.addIfNotNull(symbols, mySymbols.getPackage(fullname)); } + Collections.addAll(symbols, findGlobalType(fullname)); } private void findMemberType(Symbol s, @ShortName int name, Set symbols) throws IncompleteHierarchyException {