~~~~ switch 201 ~~~~
diff --git a/build-common/src/com/intellij/util/io/JpsPersistentHashMap.java b/build-common/src/com/intellij/util/io/JpsPersistentHashMap.java.193
similarity index 99%
rename from build-common/src/com/intellij/util/io/JpsPersistentHashMap.java
rename to build-common/src/com/intellij/util/io/JpsPersistentHashMap.java.193
index c38d1a0..1138f47 100644
--- a/build-common/src/com/intellij/util/io/JpsPersistentHashMap.java
+++ b/build-common/src/com/intellij/util/io/JpsPersistentHashMap.java.193
@@ -1,1013 +1,1013 @@
-// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
-package com.intellij.util.io;
-
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.util.LowMemoryWatcher;
-import com.intellij.openapi.util.ThreadLocalCachedValue;
-import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream;
-import com.intellij.openapi.util.io.FileUtil;
-import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.util.*;
-import com.intellij.util.containers.LimitedPool;
-import com.intellij.util.containers.SLRUCache;
-import org.jetbrains.annotations.NonNls;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-import org.jetbrains.annotations.TestOnly;
-
-import java.io.*;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
-/**
- * This class shouldn't be used. It's temporary solution for JSP only and should be removed
- * after updating Intellij SDK version
- */
-@Deprecated
-public class JpsPersistentHashMap<Key, Value> extends PersistentEnumeratorDelegate<Key> implements PersistentMap<Key, Value> {
- // PersistentHashMap (PHM) works in the following (generic) way:
- // - Particular key is translated via myEnumerator into an int.
- // - As part of enumeration process for the new key, additional space is reserved in
- // myEnumerator.myStorage for offset in ".values" file (myValueStorage) where (serialized) value is stored.
- // - Once new value is written the offset storage is updated.
- // - When the key is removed from PHM, offset storage is set to zero.
- //
- // It is important to note that offset
- // is non-negative and can be 4 or 8 bytes, depending on the size of the ".values" file.
- // PHM can work in appendable mode: for particular key additional calculated chunk of value can be appended to ".values" file with the offset
- // of previously calculated chunk.
- // For performance reasons we try hard to minimize storage occupied by keys / offsets in ".values" file: this storage is allocated as (limited)
- // direct byte buffers so 4 bytes offset is used until it is possible. Generic record produced by enumerator used with PHM as part of new
- // key enumeration is <enumerated_id>? [.values file offset 4 or 8 bytes], however for unique integral keys enumerate_id isn't produced.
- // Also for certain Value types it is possible to avoid random reads at all: e.g. in case Value is non-negative integer the value can be stored
- // directly in storage used for offset and in case of btree enumerator directly in btree leaf.
- private static final Logger LOG = Logger.getInstance("#com.intellij.util.io.PersistentHashMap");
- private static final boolean myDoTrace = SystemProperties.getBooleanProperty("idea.trace.persistent.map", false);
- private static final int DEAD_KEY_NUMBER_MASK = 0xFFFFFFFF;
-
- private final File myStorageFile;
- private final boolean myIsReadOnly;
- private final KeyDescriptor<Key> myKeyDescriptor;
- private PersistentHashMapValueStorage myValueStorage;
- protected final DataExternalizer<Value> myValueExternalizer;
- private static final long NULL_ADDR = 0;
- private static final int INITIAL_INDEX_SIZE;
-
- static {
- String property = System.getProperty("idea.initialIndexSize");
- INITIAL_INDEX_SIZE = property == null ? 4 * 1024 : Integer.valueOf(property);
- }
-
- @NonNls
- static final String DATA_FILE_EXTENSION = ".values";
- private long myLiveAndGarbageKeysCounter;
- // first four bytes contain live keys count (updated via LIVE_KEY_MASK), last four bytes - number of dead keys
- private int myReadCompactionGarbageSize;
- private static final long LIVE_KEY_MASK = 1L << 32;
- private static final long USED_LONG_VALUE_MASK = 1L << 62;
- private static final int POSITIVE_VALUE_SHIFT = 1;
- private final int myParentValueRefOffset;
- @NotNull private final byte[] myRecordBuffer;
- @NotNull private final byte[] mySmallRecordBuffer;
- private final boolean myIntMapping;
- private final boolean myDirectlyStoreLongFileOffsetMode;
- private final boolean myCanReEnumerate;
- private int myLargeIndexWatermarkId; // starting with this id we store offset in adjacent file in long format
- private boolean myIntAddressForNewRecord;
- private static final boolean doHardConsistencyChecks = false;
- private volatile boolean myBusyReading;
-
- private static class AppendStream extends DataOutputStream {
- private AppendStream() {
- super(null);
- }
-
- private void setOut(BufferExposingByteArrayOutputStream stream) {
- out = stream;
- }
- }
-
- private final LimitedPool<BufferExposingByteArrayOutputStream> myStreamPool =
- new LimitedPool<>(10, new LimitedPool.ObjectFactory<BufferExposingByteArrayOutputStream>() {
- @Override
- @NotNull
- public BufferExposingByteArrayOutputStream create() {
- return new BufferExposingByteArrayOutputStream();
- }
-
- @Override
- public void cleanup(@NotNull final BufferExposingByteArrayOutputStream appendStream) {
- appendStream.reset();
- }
- });
-
- private final SLRUCache<Key, BufferExposingByteArrayOutputStream> myAppendCache;
-
- private boolean canUseIntAddressForNewRecord(long size) {
- return myCanReEnumerate && size + POSITIVE_VALUE_SHIFT < Integer.MAX_VALUE;
- }
-
- private final LowMemoryWatcher myAppendCacheFlusher = LowMemoryWatcher.register(this::dropMemoryCaches);
-
- public JpsPersistentHashMap(@NotNull final File file,
- @NotNull KeyDescriptor<Key> keyDescriptor,
- @NotNull DataExternalizer<Value> valueExternalizer) throws IOException {
- this(file, keyDescriptor, valueExternalizer, INITIAL_INDEX_SIZE);
- }
-
- public JpsPersistentHashMap(@NotNull final File file,
- @NotNull KeyDescriptor<Key> keyDescriptor,
- @NotNull DataExternalizer<Value> valueExternalizer,
- final int initialSize) throws IOException {
- this(file, keyDescriptor, valueExternalizer, initialSize, 0);
- }
-
- public JpsPersistentHashMap(@NotNull final File file,
- @NotNull KeyDescriptor<Key> keyDescriptor,
- @NotNull DataExternalizer<Value> valueExternalizer,
- final int initialSize,
- int version) throws IOException {
- this(file, keyDescriptor, valueExternalizer, initialSize, version, null);
- }
-
- public JpsPersistentHashMap(@NotNull final File file,
- @NotNull KeyDescriptor<Key> keyDescriptor,
- @NotNull DataExternalizer<Value> valueExternalizer,
- final int initialSize,
- int version,
- @Nullable PagedFileStorage.StorageLockContext lockContext) throws IOException {
- this(file, keyDescriptor, valueExternalizer, initialSize, version, lockContext,
- PersistentHashMapValueStorage.CreationTimeOptions.threadLocalOptions());
- }
-
- private JpsPersistentHashMap(@NotNull final File file,
- @NotNull KeyDescriptor<Key> keyDescriptor,
- @NotNull DataExternalizer<Value> valueExternalizer,
- final int initialSize,
- int version,
- @Nullable PagedFileStorage.StorageLockContext lockContext,
- @NotNull PersistentHashMapValueStorage.CreationTimeOptions options) throws IOException {
- super(checkDataFiles(file), keyDescriptor, initialSize, lockContext, modifyVersionDependingOnOptions(version, options));
-
- myStorageFile = file;
- myKeyDescriptor = keyDescriptor;
- myIsReadOnly = isReadOnly();
- if (myIsReadOnly) options = options.setReadOnly();
-
- myAppendCache = createAppendCache(keyDescriptor);
- final PersistentEnumeratorBase.RecordBufferHandler<PersistentEnumeratorBase> recordHandler = myEnumerator.getRecordHandler();
- myParentValueRefOffset = recordHandler.getRecordBuffer(myEnumerator).length;
- myIntMapping = valueExternalizer instanceof IntInlineKeyDescriptor && wantNonNegativeIntegralValues();
- myDirectlyStoreLongFileOffsetMode = keyDescriptor instanceof InlineKeyDescriptor && myEnumerator instanceof PersistentBTreeEnumerator;
-
- myRecordBuffer = myDirectlyStoreLongFileOffsetMode ? ArrayUtilRt.EMPTY_BYTE_ARRAY : new byte[myParentValueRefOffset + 8];
- mySmallRecordBuffer = myDirectlyStoreLongFileOffsetMode ? ArrayUtilRt.EMPTY_BYTE_ARRAY : new byte[myParentValueRefOffset + 4];
-
- myEnumerator.setRecordHandler(new PersistentEnumeratorBase.RecordBufferHandler<PersistentEnumeratorBase>() {
- @Override
- int recordWriteOffset(PersistentEnumeratorBase enumerator, byte[] buf) {
- return recordHandler.recordWriteOffset(enumerator, buf);
- }
-
- @NotNull
- @Override
- byte[] getRecordBuffer(PersistentEnumeratorBase enumerator) {
- return myIntAddressForNewRecord ? mySmallRecordBuffer : myRecordBuffer;
- }
-
- @Override
- void setupRecord(PersistentEnumeratorBase enumerator, int hashCode, int dataOffset, @NotNull byte[] buf) {
- recordHandler.setupRecord(enumerator, hashCode, dataOffset, buf);
- for (int i = myParentValueRefOffset; i < buf.length; i++) {
- buf[i] = 0;
- }
- }
- });
-
- myEnumerator.setMarkCleanCallback(
- new Flushable() {
- @Override
- public void flush() {
- myEnumerator.putMetaData(myLiveAndGarbageKeysCounter);
- myEnumerator.putMetaData2(myLargeIndexWatermarkId | ((long)myReadCompactionGarbageSize << 32));
- }
- }
- );
-
- if (myDoTrace) LOG.info("Opened " + file);
- try {
- myValueExternalizer = valueExternalizer;
- myValueStorage = PersistentHashMapValueStorage.create(getDataFile(file).getPath(), options);
- myLiveAndGarbageKeysCounter = myEnumerator.getMetaData();
- long data2 = myEnumerator.getMetaData2();
- myLargeIndexWatermarkId = (int)(data2 & DEAD_KEY_NUMBER_MASK);
- myReadCompactionGarbageSize = (int)(data2 >>> 32);
- myCanReEnumerate = myEnumerator.canReEnumerate();
-
- if (makesSenseToCompact()) {
- compact();
- }
- }
- catch (IOException e) {
- try {
- // attempt to close already opened resources
- close();
- }
- catch (Throwable ignored) {
- }
- throw e; // rethrow
- }
- catch (Throwable t) {
- LOG.error(t);
- try {
- // attempt to close already opened resources
- close();
- }
- catch (Throwable ignored) {
- }
- throw new PersistentEnumerator.CorruptedException(file);
- }
- }
-
- private static int modifyVersionDependingOnOptions(int version, @NotNull PersistentHashMapValueStorage.CreationTimeOptions options) {
- return version + options.getVersion();
- }
-
- protected boolean wantNonNegativeIntegralValues() {
- return false;
- }
-
- protected boolean isReadOnly() {
- return false;
- }
-
- private static final int MAX_RECYCLED_BUFFER_SIZE = 4096;
-
- private SLRUCache<Key, BufferExposingByteArrayOutputStream> createAppendCache(final KeyDescriptor<Key> keyDescriptor) {
- return new SLRUCache<Key, BufferExposingByteArrayOutputStream>(16 * 1024, 4 * 1024, keyDescriptor) {
- @Override
- @NotNull
- public BufferExposingByteArrayOutputStream createValue(final Key key) {
- return myStreamPool.alloc();
- }
-
- @Override
- protected void onDropFromCache(final Key key, @NotNull final BufferExposingByteArrayOutputStream bytes) {
- appendDataWithoutCache(key, bytes);
- }
- };
- }
-
- private static boolean doNewCompact() {
- return System.getProperty("idea.persistent.hash.map.oldcompact") == null;
- }
-
- private boolean forceNewCompact() {
- return System.getProperty("idea.persistent.hash.map.newcompact") != null &&
- (int)(myLiveAndGarbageKeysCounter & DEAD_KEY_NUMBER_MASK) > 0;
- }
-
- public final void dropMemoryCaches() {
- if (myDoTrace) LOG.info("Drop memory caches " + myStorageFile);
- synchronized (myEnumerator) {
- doDropMemoryCaches();
- }
- }
-
- protected void doDropMemoryCaches() {
- myEnumerator.lockStorage();
- try {
- clearAppenderCaches();
- }
- finally {
- myEnumerator.unlockStorage();
- }
- }
-
- int getGarbageSize() {
- return (int)myLiveAndGarbageKeysCounter;
- }
-
- public File getBaseFile() {
- return myEnumerator.myFile;
- }
-
- @TestOnly // public for tests
- @SuppressWarnings("WeakerAccess") // used in upsource for some reason
- public boolean makesSenseToCompact() {
- if (myIsReadOnly) return false;
-
- final long fileSize = myValueStorage.getSize();
- final int megabyte = 1024 * 1024;
-
- if (fileSize > 5 * megabyte) { // file is longer than 5MB and (more than 50% of keys is garbage or approximate benefit larger than 100M)
- int liveKeys = (int)(myLiveAndGarbageKeysCounter / LIVE_KEY_MASK);
- int deadKeys = (int)(myLiveAndGarbageKeysCounter & DEAD_KEY_NUMBER_MASK);
-
- if (fileSize > 50 * megabyte && forceNewCompact()) return true;
- if (deadKeys < 50) return false;
-
- final long benefitSize = Math.max(100 * megabyte, fileSize / 4);
- final long avgValueSize = fileSize / (liveKeys + deadKeys);
-
- return deadKeys > liveKeys ||
- avgValueSize * deadKeys > benefitSize ||
- myReadCompactionGarbageSize > fileSize / 2;
- }
- return false;
- }
-
- @NotNull
- private static File checkDataFiles(@NotNull final File file) {
- if (!file.exists()) {
- deleteFilesStartingWith(getDataFile(file));
- }
- return file;
- }
-
- public static void deleteFilesStartingWith(@NotNull File prefixFile) {
- IOUtil.deleteAllFilesStartingWith(prefixFile);
- }
-
- @NotNull
- static File getDataFile(@NotNull final File file) { // made public for testing
- return new File(file.getParentFile(), file.getName() + DATA_FILE_EXTENSION);
- }
-
- @Override
- public final void put(Key key, Value value) throws IOException {
- if (myIsReadOnly) throw new IncorrectOperationException();
- synchronized (myEnumerator) {
- try {
- doPut(key, value);
- }
- catch (IOException ex) {
- myEnumerator.markCorrupted();
- throw ex;
- }
- }
- }
-
- protected void doPut(Key key, Value value) throws IOException {
- long newValueOffset = -1;
-
- if (!myIntMapping) {
- final BufferExposingByteArrayOutputStream bytes = new BufferExposingByteArrayOutputStream();
- AppendStream appenderStream = ourFlyweightAppenderStream.getValue();
- appenderStream.setOut(bytes);
- myValueExternalizer.save(appenderStream, value);
- appenderStream.setOut(null);
- newValueOffset = myValueStorage.appendBytes(bytes.toByteArraySequence(), 0);
- }
-
- myEnumerator.lockStorage();
- try {
- myEnumerator.markDirty(true);
- myAppendCache.remove(key);
-
- long oldValueOffset;
- if (myDirectlyStoreLongFileOffsetMode) {
- if (myIntMapping) {
- ((PersistentBTreeEnumerator<Key>)myEnumerator).putNonNegativeValue(key, (Integer)value);
- return;
- }
- oldValueOffset = ((PersistentBTreeEnumerator<Key>)myEnumerator).getNonNegativeValue(key);
- ((PersistentBTreeEnumerator<Key>)myEnumerator).putNonNegativeValue(key, newValueOffset);
- }
- else {
- final int id = enumerate(key);
- if (myIntMapping) {
- myEnumerator.myStorage.putInt(id + myParentValueRefOffset, (Integer)value);
- return;
- }
-
- oldValueOffset = readValueId(id);
- updateValueId(id, newValueOffset, oldValueOffset, key, 0);
- }
-
- if (oldValueOffset != NULL_ADDR) {
- myLiveAndGarbageKeysCounter++;
- }
- else {
- myLiveAndGarbageKeysCounter += LIVE_KEY_MASK;
- }
- }
- finally {
- myEnumerator.unlockStorage();
- }
- }
-
- @Override
- public final int enumerate(Key name) throws IOException {
- if (myIsReadOnly) throw new IncorrectOperationException();
- synchronized (myEnumerator) {
- myIntAddressForNewRecord = canUseIntAddressForNewRecord(myValueStorage.getSize());
- return super.enumerate(name);
- }
- }
-
- /**
- * Appends value chunk from specified appender to key's value.
- * Important use note: value externalizer used by this map should process all bytes from DataInput during deserialization and make sure
- * that deserialized value is consistent with value chunks appended.
- * E.g. Value can be Set of String and individual Strings can be appended with this method for particular key, when {@link #get(Object)} will
- * be eventually called for the key, deserializer will read all bytes retrieving Strings and collecting them into Set
- */
- public final void appendData(Key key, @NotNull PersistentHashMap.ValueDataAppender appender) throws IOException {
- if (myIsReadOnly) throw new IncorrectOperationException();
- synchronized (myEnumerator) {
- try {
- doAppendData(key, appender);
- }
- catch (IOException ex) {
- myEnumerator.markCorrupted();
- throw ex;
- }
- }
- }
-
- public final void appendDataWithoutCache(Key key, Value value) throws IOException {
- synchronized (myEnumerator) {
- try {
- final BufferExposingByteArrayOutputStream bytes = new BufferExposingByteArrayOutputStream();
- AppendStream appenderStream = ourFlyweightAppenderStream.getValue();
- appenderStream.setOut(bytes);
- myValueExternalizer.save(appenderStream, value);
- appenderStream.setOut(null);
- appendDataWithoutCache(key, bytes);
- }
- catch (IOException ex) {
- markCorrupted();
- throw ex;
- }
- }
- }
-
- private void appendDataWithoutCache(Key key, @NotNull final BufferExposingByteArrayOutputStream bytes) {
- myEnumerator.lockStorage();
- try {
- long previousRecord;
- final int id;
- if (myDirectlyStoreLongFileOffsetMode) {
- previousRecord = ((PersistentBTreeEnumerator<Key>)myEnumerator).getNonNegativeValue(key);
- id = -1;
- }
- else {
- id = enumerate(key);
- previousRecord = readValueId(id);
- }
-
- long headerRecord = myValueStorage.appendBytes(bytes.toByteArraySequence(), previousRecord);
-
- if (myDirectlyStoreLongFileOffsetMode) {
- ((PersistentBTreeEnumerator<Key>)myEnumerator).putNonNegativeValue(key, headerRecord);
- }
- else {
- updateValueId(id, headerRecord, previousRecord, key, 0);
- }
-
- if (previousRecord == NULL_ADDR) {
- myLiveAndGarbageKeysCounter += LIVE_KEY_MASK;
- }
-
- if (bytes.getInternalBuffer().length <= MAX_RECYCLED_BUFFER_SIZE) {
- // Avoid internal fragmentation by not retaining / reusing large append buffers (IDEA-208533)
- myStreamPool.recycle(bytes);
- }
- }
- catch (IOException e) {
- markCorrupted();
- throw new RuntimeException(e);
- }
- finally {
- myEnumerator.unlockStorage();
- }
- }
-
- private static final ThreadLocalCachedValue<AppendStream> ourFlyweightAppenderStream = new ThreadLocalCachedValue<AppendStream>() {
- @NotNull
- @Override
- protected AppendStream create() {
- return new AppendStream();
- }
- };
-
- private void doAppendData(Key key, @NotNull PersistentHashMap.ValueDataAppender appender) throws IOException {
- assert !myIntMapping;
- myEnumerator.markDirty(true);
-
- AppendStream appenderStream = ourFlyweightAppenderStream.getValue();
- BufferExposingByteArrayOutputStream stream = myAppendCache.get(key);
- appenderStream.setOut(stream);
- myValueStorage.checkAppendsAllowed(stream.size());
- appender.append(appenderStream);
- appenderStream.setOut(null);
- }
-
- /**
- * Process all keys registered in the map. Note that keys which were removed after {@link #compact()} call will be processed as well. Use
- * {@link #processKeysWithExistingMapping(Processor)} to process only keys with existing mappings
- */
- @Override
- public final boolean processKeys(@NotNull Processor<? super Key> processor) throws IOException {
- synchronized (myEnumerator) {
- try {
- myAppendCache.clear();
- return myEnumerator.iterateData(processor);
- }
- catch (IOException e) {
- myEnumerator.markCorrupted();
- throw e;
- }
- }
- }
-
- @NotNull
- public Collection<Key> getAllKeysWithExistingMapping() throws IOException {
- final List<Key> values = new ArrayList<>();
- processKeysWithExistingMapping(new CommonProcessors.CollectProcessor<>(values));
- return values;
- }
-
- public final boolean processKeysWithExistingMapping(Processor<? super Key> processor) throws IOException {
- synchronized (myEnumerator) {
- try {
- myAppendCache.clear();
- return myEnumerator.processAllDataObject(processor, new PersistentEnumerator.DataFilter() {
- @Override
- public boolean accept(final int id) {
- return readValueId(id) != NULL_ADDR;
- }
- });
- }
- catch (IOException e) {
- myEnumerator.markCorrupted();
- throw e;
- }
- }
- }
-
- @Override
- public final Value get(Key key) throws IOException {
- synchronized (myEnumerator) {
- myBusyReading = true;
- try {
- return doGet(key);
- }
- catch (IOException ex) {
- myEnumerator.markCorrupted();
- throw ex;
- }
- finally {
- myBusyReading = false;
- }
- }
- }
-
- public boolean isBusyReading() {
- return myBusyReading;
- }
-
- @Nullable
- protected Value doGet(Key key) throws IOException {
- myEnumerator.lockStorage();
- final long valueOffset;
- final int id;
- try {
- myAppendCache.remove(key);
-
- if (myDirectlyStoreLongFileOffsetMode) {
- valueOffset = ((PersistentBTreeEnumerator<Key>)myEnumerator).getNonNegativeValue(key);
- if (myIntMapping) {
- return (Value)(Integer)(int)valueOffset;
- }
- id = -1;
- }
- else {
- id = tryEnumerate(key);
- if (id == PersistentEnumeratorBase.NULL_ID) {
- return null;
- }
-
- if (myIntMapping) {
- return (Value)(Integer)myEnumerator.myStorage.getInt(id + myParentValueRefOffset);
- }
-
- valueOffset = readValueId(id);
- }
-
- if (valueOffset == NULL_ADDR) {
- return null;
- }
- }
- finally {
- myEnumerator.unlockStorage();
- }
-
- final PersistentHashMapValueStorage.ReadResult readResult = myValueStorage.readBytes(valueOffset);
-
- final Value valueRead;
- try (DataInputStream input = new DataInputStream(new UnsyncByteArrayInputStream(readResult.buffer))) {
- valueRead = myValueExternalizer.read(input);
- }
-
- if (myValueStorage.performChunksCompaction(readResult.chunksCount, readResult.buffer.length)) {
-
- long newValueOffset = myValueStorage.compactChunks(new PersistentHashMap.ValueDataAppender() {
- @Override
- public void append(DataOutput out) throws IOException {
- myValueExternalizer.save(out, valueRead);
- }
- }, readResult);
-
- myEnumerator.lockStorage();
- try {
- myEnumerator.markDirty(true);
-
- if (myDirectlyStoreLongFileOffsetMode) {
- ((PersistentBTreeEnumerator<Key>)myEnumerator).putNonNegativeValue(key, newValueOffset);
- }
- else {
- updateValueId(id, newValueOffset, valueOffset, key, 0);
- }
- myLiveAndGarbageKeysCounter++;
- myReadCompactionGarbageSize += readResult.buffer.length;
- }
- finally {
- myEnumerator.unlockStorage();
- }
- }
- return valueRead;
- }
-
- public final boolean containsMapping(Key key) throws IOException {
- synchronized (myEnumerator) {
- return doContainsMapping(key);
- }
- }
-
- private boolean doContainsMapping(Key key) throws IOException {
- myEnumerator.lockStorage();
- try {
- myAppendCache.remove(key);
- if (myDirectlyStoreLongFileOffsetMode) {
- return ((PersistentBTreeEnumerator<Key>)myEnumerator).getNonNegativeValue(key) != NULL_ADDR;
- }
- else {
- final int id = tryEnumerate(key);
- if (id == PersistentEnumeratorBase.NULL_ID) {
- return false;
- }
- if (myIntMapping) return true;
- return readValueId(id) != NULL_ADDR;
- }
- }
- finally {
- myEnumerator.unlockStorage();
- }
- }
-
- public final void remove(Key key) throws IOException {
- if (myIsReadOnly) throw new IncorrectOperationException();
- synchronized (myEnumerator) {
- doRemove(key);
- }
- }
-
- protected void doRemove(Key key) throws IOException {
- myEnumerator.lockStorage();
- try {
-
- myAppendCache.remove(key);
- final long record;
- if (myDirectlyStoreLongFileOffsetMode) {
- assert !myIntMapping; // removal isn't supported
- record = ((PersistentBTreeEnumerator<Key>)myEnumerator).getNonNegativeValue(key);
- if (record != NULL_ADDR) {
- ((PersistentBTreeEnumerator<Key>)myEnumerator).putNonNegativeValue(key, NULL_ADDR);
- }
- }
- else {
- final int id = tryEnumerate(key);
- if (id == PersistentEnumeratorBase.NULL_ID) {
- return;
- }
- assert !myIntMapping; // removal isn't supported
- myEnumerator.markDirty(true);
-
- record = readValueId(id);
- updateValueId(id, NULL_ADDR, record, key, 0);
- }
- if (record != NULL_ADDR) {
- myLiveAndGarbageKeysCounter++;
- myLiveAndGarbageKeysCounter -= LIVE_KEY_MASK;
- }
- }
- finally {
- myEnumerator.unlockStorage();
- }
- }
-
- @Override
- public final void force() {
- if (myIsReadOnly) return;
- if (myDoTrace) LOG.info("Forcing " + myStorageFile);
- synchronized (myEnumerator) {
- doForce();
- }
- }
-
- protected void doForce() {
- myEnumerator.lockStorage();
- try {
- try {
- clearAppenderCaches();
- }
- finally {
- super.force();
- }
- }
- finally {
- myEnumerator.unlockStorage();
- }
- }
-
- private void clearAppenderCaches() {
- myAppendCache.clear();
- myValueStorage.force();
- }
-
- @Override
- public final void close() throws IOException {
- if (myDoTrace) LOG.info("Closed " + myStorageFile);
- synchronized (myEnumerator) {
- doClose();
- }
- }
-
- private void doClose() throws IOException {
- myEnumerator.lockStorage();
- try {
- try {
- myAppendCacheFlusher.stop();
- try {
- myAppendCache.clear();
- }
- catch (RuntimeException ex) {
- Throwable cause = ex.getCause();
- if (cause instanceof IOException) throw (IOException)cause;
- throw ex;
- }
- }
- finally {
- final PersistentHashMapValueStorage valueStorage = myValueStorage;
- try {
- if (valueStorage != null) {
- valueStorage.dispose();
- }
- }
- finally {
- super.close();
- }
- }
- }
- finally {
- myEnumerator.unlockStorage();
- }
- }
-
- //static class CompactionRecordInfo {
- // final int key;
- // final int address;
- // long valueAddress;
- // long newValueAddress;
- // byte[] value;
- //
- // CompactionRecordInfo(int _key, long _valueAddress, int _address) {
- // key = _key;
- // address = _address;
- // valueAddress = _valueAddress;
- // }
- //}
-
- // made public for tests
- public void compact() throws IOException {
- if (myIsReadOnly) throw new IncorrectOperationException();
- synchronized (myEnumerator) {
- force();
- LOG.info("Compacting " + myEnumerator.myFile.getPath());
- LOG.info("Live keys:" + (int)(myLiveAndGarbageKeysCounter / LIVE_KEY_MASK) +
- ", dead keys:" + (int)(myLiveAndGarbageKeysCounter & DEAD_KEY_NUMBER_MASK) +
- ", read compaction size:" + myReadCompactionGarbageSize);
-
- final long now = System.currentTimeMillis();
-
- final File oldDataFile = getDataFile(myEnumerator.myFile);
- final String oldDataFileBaseName = oldDataFile.getName();
- final File[] oldFiles = getFilesInDirectoryWithNameStartingWith(oldDataFile, oldDataFileBaseName);
-
- final String newPath = getDataFile(myEnumerator.myFile).getPath() + ".new";
- PersistentHashMapValueStorage.CreationTimeOptions options = myValueStorage.getOptions();
- final PersistentHashMapValueStorage newStorage = PersistentHashMapValueStorage.create(newPath, options);
- myValueStorage.switchToCompactionMode();
- myEnumerator.markDirty(true);
- long sizeBefore = myValueStorage.getSize();
-
- myLiveAndGarbageKeysCounter = 0;
- myReadCompactionGarbageSize = 0;
-
- try {
- if (doNewCompact()) {
- newCompact(newStorage);
- }
- else {
- traverseAllRecords(new PersistentEnumerator.RecordsProcessor() {
- @Override
- public boolean process(final int keyId) throws IOException {
- final long record = readValueId(keyId);
- if (record != NULL_ADDR) {
- PersistentHashMapValueStorage.ReadResult readResult = myValueStorage.readBytes(record);
- long value = newStorage.appendBytes(readResult.buffer, 0, readResult.buffer.length, 0);
- updateValueId(keyId, value, record, null, getCurrentKey());
- myLiveAndGarbageKeysCounter += LIVE_KEY_MASK;
- }
- return true;
- }
- });
- }
- }
- finally {
- newStorage.dispose();
- }
-
- myValueStorage.dispose();
-
- if (oldFiles != null) {
- for (File f : oldFiles) {
- assert FileUtil.deleteWithRenaming(f);
- }
- }
-
- final long newSize = newStorage.getSize();
-
- File newDataFile = new File(newPath);
- final String newBaseName = newDataFile.getName();
- final File[] newFiles = getFilesInDirectoryWithNameStartingWith(newDataFile, newBaseName);
-
- if (newFiles != null) {
- File parentFile = newDataFile.getParentFile();
-
- // newFiles should get the same names as oldDataFiles
- for (File f : newFiles) {
- String nameAfterRename = StringUtil.replace(f.getName(), newBaseName, oldDataFileBaseName);
- FileUtil.rename(f, new File(parentFile, nameAfterRename));
- }
- }
-
- myValueStorage = PersistentHashMapValueStorage.create(oldDataFile.getPath(), options);
- LOG.info("Compacted " + myEnumerator.myFile.getPath() + ":" + sizeBefore + " bytes into " +
- newSize + " bytes in " + (System.currentTimeMillis() - now) + "ms.");
- myEnumerator.putMetaData(myLiveAndGarbageKeysCounter);
- myEnumerator.putMetaData2(myLargeIndexWatermarkId);
- if (myDoTrace) LOG.assertTrue(myEnumerator.isDirty());
- }
- }
-
- private static File[] getFilesInDirectoryWithNameStartingWith(@NotNull File fileFromDirectory, @NotNull final String baseFileName) {
- File parentFile = fileFromDirectory.getParentFile();
- return parentFile != null ? parentFile.listFiles(pathname -> pathname.getName().startsWith(baseFileName)) : null;
- }
-
- private void newCompact(@NotNull PersistentHashMapValueStorage newStorage) throws IOException {
- long started = System.currentTimeMillis();
- final List<PersistentHashMap.CompactionRecordInfo> infos = new ArrayList<>(10000);
-
- traverseAllRecords(new PersistentEnumerator.RecordsProcessor() {
- @Override
- public boolean process(final int keyId) {
- final long record = readValueId(keyId);
- if (record != NULL_ADDR) {
- infos.add(new PersistentHashMap.CompactionRecordInfo(getCurrentKey(), record, keyId));
- }
- return true;
- }
- });
-
- LOG.info("Loaded mappings:" + (System.currentTimeMillis() - started) + "ms, keys:" + infos.size());
- started = System.currentTimeMillis();
- long fragments = 0;
- if (!infos.isEmpty()) {
- try {
- fragments = myValueStorage.compactValues(infos, newStorage);
- }
- catch (Throwable t) {
- if (!(t instanceof IOException)) throw new IOException("Compaction failed", t);
- throw (IOException)t;
- }
- }
-
- LOG.info("Compacted values for:" + (System.currentTimeMillis() - started) + "ms fragments:" +
- (int)fragments + ", new fragments:" + (fragments >> 32));
-
- started = System.currentTimeMillis();
- try {
- myEnumerator.lockStorage();
-
- for (PersistentHashMap.CompactionRecordInfo info : infos) {
- updateValueId(info.address, info.newValueAddress, info.valueAddress, null, info.key);
- myLiveAndGarbageKeysCounter += LIVE_KEY_MASK;
- }
- }
- finally {
- myEnumerator.unlockStorage();
- }
- LOG.info("Updated mappings:" + (System.currentTimeMillis() - started) + " ms");
- }
-
- private long readValueId(final int keyId) {
- if (myDirectlyStoreLongFileOffsetMode) {
- return ((PersistentBTreeEnumerator<Key>)myEnumerator).keyIdToNonNegativeOffset(keyId);
- }
- long address = myEnumerator.myStorage.getInt(keyId + myParentValueRefOffset);
- if (address == 0 || address == -POSITIVE_VALUE_SHIFT) {
- return NULL_ADDR;
- }
-
- if (address < 0) {
- address = -address - POSITIVE_VALUE_SHIFT;
- }
- else {
- long value = myEnumerator.myStorage.getInt(keyId + myParentValueRefOffset + 4) & 0xFFFFFFFFL;
- address = ((address << 32) + value) & ~USED_LONG_VALUE_MASK;
- }
-
- return address;
- }
-
- private int smallKeys;
- private int largeKeys;
- private int transformedKeys;
- private int requests;
-
- private int updateValueId(int keyId, long value, long oldValue, @Nullable Key key, int processingKey) throws IOException {
- if (myDirectlyStoreLongFileOffsetMode) {
- ((PersistentBTreeEnumerator<Key>)myEnumerator).putNonNegativeValue(((InlineKeyDescriptor<Key>)myKeyDescriptor).fromInt(processingKey), value);
- return keyId;
- }
- final boolean newKey = oldValue == NULL_ADDR;
- if (newKey) ++requests;
- boolean defaultSizeInfo = true;
-
- if (myCanReEnumerate) {
- if (canUseIntAddressForNewRecord(value)) {
- defaultSizeInfo = false;
- myEnumerator.myStorage.putInt(keyId + myParentValueRefOffset, -(int)(value + POSITIVE_VALUE_SHIFT));
- if (newKey) ++smallKeys;
- }
- else if ((keyId < myLargeIndexWatermarkId || myLargeIndexWatermarkId == 0) && (newKey || canUseIntAddressForNewRecord(oldValue))) {
- // keyId is result of enumerate, if we do re-enumerate then it is no longer accessible unless somebody cached it
- myIntAddressForNewRecord = false;
- keyId = myEnumerator.reEnumerate(key == null ? myEnumerator.getValue(keyId, processingKey) : key);
- ++transformedKeys;
- if (myLargeIndexWatermarkId == 0) {
- myLargeIndexWatermarkId = keyId;
- }
- }
- }
-
- if (defaultSizeInfo) {
- value |= USED_LONG_VALUE_MASK;
-
- myEnumerator.myStorage.putInt(keyId + myParentValueRefOffset, (int)(value >>> 32));
- myEnumerator.myStorage.putInt(keyId + myParentValueRefOffset + 4, (int)value);
-
- if (newKey) ++largeKeys;
- }
-
- if (newKey && IOStatistics.DEBUG && (requests & IOStatistics.KEYS_FACTOR_MASK) == 0) {
- IOStatistics.dump("small:" + smallKeys + ", large:" + largeKeys + ", transformed:" + transformedKeys +
- ",@" + getBaseFile().getPath());
- }
- if (doHardConsistencyChecks) {
- long checkRecord = readValueId(keyId);
- assert checkRecord == (value & ~USED_LONG_VALUE_MASK) : value;
- }
- return keyId;
- }
-
- @Override
- public String toString() {
- return super.toString() + ": " + myStorageFile;
- }
-
- @TestOnly
- PersistentHashMapValueStorage getValueStorage() {
- return myValueStorage;
- }
-
- @TestOnly
- public boolean getReadOnly() {
- return myIsReadOnly;
- }
-}
+// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+package com.intellij.util.io;
+
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.util.LowMemoryWatcher;
+import com.intellij.openapi.util.ThreadLocalCachedValue;
+import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.util.*;
+import com.intellij.util.containers.LimitedPool;
+import com.intellij.util.containers.SLRUCache;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.annotations.TestOnly;
+
+import java.io.*;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * This class shouldn't be used. It's temporary solution for JSP only and should be removed
+ * after updating Intellij SDK version
+ */
+@Deprecated
+public class JpsPersistentHashMap<Key, Value> extends PersistentEnumeratorDelegate<Key> implements PersistentMap<Key, Value> {
+ // PersistentHashMap (PHM) works in the following (generic) way:
+ // - Particular key is translated via myEnumerator into an int.
+ // - As part of enumeration process for the new key, additional space is reserved in
+ // myEnumerator.myStorage for offset in ".values" file (myValueStorage) where (serialized) value is stored.
+ // - Once new value is written the offset storage is updated.
+ // - When the key is removed from PHM, offset storage is set to zero.
+ //
+ // It is important to note that offset
+ // is non-negative and can be 4 or 8 bytes, depending on the size of the ".values" file.
+ // PHM can work in appendable mode: for particular key additional calculated chunk of value can be appended to ".values" file with the offset
+ // of previously calculated chunk.
+ // For performance reasons we try hard to minimize storage occupied by keys / offsets in ".values" file: this storage is allocated as (limited)
+ // direct byte buffers so 4 bytes offset is used until it is possible. Generic record produced by enumerator used with PHM as part of new
+ // key enumeration is <enumerated_id>? [.values file offset 4 or 8 bytes], however for unique integral keys enumerate_id isn't produced.
+ // Also for certain Value types it is possible to avoid random reads at all: e.g. in case Value is non-negative integer the value can be stored
+ // directly in storage used for offset and in case of btree enumerator directly in btree leaf.
+ private static final Logger LOG = Logger.getInstance("#com.intellij.util.io.PersistentHashMap");
+ private static final boolean myDoTrace = SystemProperties.getBooleanProperty("idea.trace.persistent.map", false);
+ private static final int DEAD_KEY_NUMBER_MASK = 0xFFFFFFFF;
+
+ private final File myStorageFile;
+ private final boolean myIsReadOnly;
+ private final KeyDescriptor<Key> myKeyDescriptor;
+ private PersistentHashMapValueStorage myValueStorage;
+ protected final DataExternalizer<Value> myValueExternalizer;
+ private static final long NULL_ADDR = 0;
+ private static final int INITIAL_INDEX_SIZE;
+
+ static {
+ String property = System.getProperty("idea.initialIndexSize");
+ INITIAL_INDEX_SIZE = property == null ? 4 * 1024 : Integer.valueOf(property);
+ }
+
+ @NonNls
+ static final String DATA_FILE_EXTENSION = ".values";
+ private long myLiveAndGarbageKeysCounter;
+ // first four bytes contain live keys count (updated via LIVE_KEY_MASK), last four bytes - number of dead keys
+ private int myReadCompactionGarbageSize;
+ private static final long LIVE_KEY_MASK = 1L << 32;
+ private static final long USED_LONG_VALUE_MASK = 1L << 62;
+ private static final int POSITIVE_VALUE_SHIFT = 1;
+ private final int myParentValueRefOffset;
+ @NotNull private final byte[] myRecordBuffer;
+ @NotNull private final byte[] mySmallRecordBuffer;
+ private final boolean myIntMapping;
+ private final boolean myDirectlyStoreLongFileOffsetMode;
+ private final boolean myCanReEnumerate;
+ private int myLargeIndexWatermarkId; // starting with this id we store offset in adjacent file in long format
+ private boolean myIntAddressForNewRecord;
+ private static final boolean doHardConsistencyChecks = false;
+ private volatile boolean myBusyReading;
+
+ private static class AppendStream extends DataOutputStream {
+ private AppendStream() {
+ super(null);
+ }
+
+ private void setOut(BufferExposingByteArrayOutputStream stream) {
+ out = stream;
+ }
+ }
+
+ private final LimitedPool<BufferExposingByteArrayOutputStream> myStreamPool =
+ new LimitedPool<>(10, new LimitedPool.ObjectFactory<BufferExposingByteArrayOutputStream>() {
+ @Override
+ @NotNull
+ public BufferExposingByteArrayOutputStream create() {
+ return new BufferExposingByteArrayOutputStream();
+ }
+
+ @Override
+ public void cleanup(@NotNull final BufferExposingByteArrayOutputStream appendStream) {
+ appendStream.reset();
+ }
+ });
+
+ private final SLRUCache<Key, BufferExposingByteArrayOutputStream> myAppendCache;
+
+ private boolean canUseIntAddressForNewRecord(long size) {
+ return myCanReEnumerate && size + POSITIVE_VALUE_SHIFT < Integer.MAX_VALUE;
+ }
+
+ private final LowMemoryWatcher myAppendCacheFlusher = LowMemoryWatcher.register(this::dropMemoryCaches);
+
+ public JpsPersistentHashMap(@NotNull final File file,
+ @NotNull KeyDescriptor<Key> keyDescriptor,
+ @NotNull DataExternalizer<Value> valueExternalizer) throws IOException {
+ this(file, keyDescriptor, valueExternalizer, INITIAL_INDEX_SIZE);
+ }
+
+ public JpsPersistentHashMap(@NotNull final File file,
+ @NotNull KeyDescriptor<Key> keyDescriptor,
+ @NotNull DataExternalizer<Value> valueExternalizer,
+ final int initialSize) throws IOException {
+ this(file, keyDescriptor, valueExternalizer, initialSize, 0);
+ }
+
+ public JpsPersistentHashMap(@NotNull final File file,
+ @NotNull KeyDescriptor<Key> keyDescriptor,
+ @NotNull DataExternalizer<Value> valueExternalizer,
+ final int initialSize,
+ int version) throws IOException {
+ this(file, keyDescriptor, valueExternalizer, initialSize, version, null);
+ }
+
+ public JpsPersistentHashMap(@NotNull final File file,
+ @NotNull KeyDescriptor<Key> keyDescriptor,
+ @NotNull DataExternalizer<Value> valueExternalizer,
+ final int initialSize,
+ int version,
+ @Nullable PagedFileStorage.StorageLockContext lockContext) throws IOException {
+ this(file, keyDescriptor, valueExternalizer, initialSize, version, lockContext,
+ PersistentHashMapValueStorage.CreationTimeOptions.threadLocalOptions());
+ }
+
+ private JpsPersistentHashMap(@NotNull final File file,
+ @NotNull KeyDescriptor<Key> keyDescriptor,
+ @NotNull DataExternalizer<Value> valueExternalizer,
+ final int initialSize,
+ int version,
+ @Nullable PagedFileStorage.StorageLockContext lockContext,
+ @NotNull PersistentHashMapValueStorage.CreationTimeOptions options) throws IOException {
+ super(checkDataFiles(file), keyDescriptor, initialSize, lockContext, modifyVersionDependingOnOptions(version, options));
+
+ myStorageFile = file;
+ myKeyDescriptor = keyDescriptor;
+ myIsReadOnly = isReadOnly();
+ if (myIsReadOnly) options = options.setReadOnly();
+
+ myAppendCache = createAppendCache(keyDescriptor);
+ final PersistentEnumeratorBase.RecordBufferHandler<PersistentEnumeratorBase> recordHandler = myEnumerator.getRecordHandler();
+ myParentValueRefOffset = recordHandler.getRecordBuffer(myEnumerator).length;
+ myIntMapping = valueExternalizer instanceof IntInlineKeyDescriptor && wantNonNegativeIntegralValues();
+ myDirectlyStoreLongFileOffsetMode = keyDescriptor instanceof InlineKeyDescriptor && myEnumerator instanceof PersistentBTreeEnumerator;
+
+ myRecordBuffer = myDirectlyStoreLongFileOffsetMode ? ArrayUtilRt.EMPTY_BYTE_ARRAY : new byte[myParentValueRefOffset + 8];
+ mySmallRecordBuffer = myDirectlyStoreLongFileOffsetMode ? ArrayUtilRt.EMPTY_BYTE_ARRAY : new byte[myParentValueRefOffset + 4];
+
+ myEnumerator.setRecordHandler(new PersistentEnumeratorBase.RecordBufferHandler<PersistentEnumeratorBase>() {
+ @Override
+ int recordWriteOffset(PersistentEnumeratorBase enumerator, byte[] buf) {
+ return recordHandler.recordWriteOffset(enumerator, buf);
+ }
+
+ @NotNull
+ @Override
+ byte[] getRecordBuffer(PersistentEnumeratorBase enumerator) {
+ return myIntAddressForNewRecord ? mySmallRecordBuffer : myRecordBuffer;
+ }
+
+ @Override
+ void setupRecord(PersistentEnumeratorBase enumerator, int hashCode, int dataOffset, @NotNull byte[] buf) {
+ recordHandler.setupRecord(enumerator, hashCode, dataOffset, buf);
+ for (int i = myParentValueRefOffset; i < buf.length; i++) {
+ buf[i] = 0;
+ }
+ }
+ });
+
+ myEnumerator.setMarkCleanCallback(
+ new Flushable() {
+ @Override
+ public void flush() {
+ myEnumerator.putMetaData(myLiveAndGarbageKeysCounter);
+ myEnumerator.putMetaData2(myLargeIndexWatermarkId | ((long)myReadCompactionGarbageSize << 32));
+ }
+ }
+ );
+
+ if (myDoTrace) LOG.info("Opened " + file);
+ try {
+ myValueExternalizer = valueExternalizer;
+ myValueStorage = PersistentHashMapValueStorage.create(getDataFile(file).getPath(), options);
+ myLiveAndGarbageKeysCounter = myEnumerator.getMetaData();
+ long data2 = myEnumerator.getMetaData2();
+ myLargeIndexWatermarkId = (int)(data2 & DEAD_KEY_NUMBER_MASK);
+ myReadCompactionGarbageSize = (int)(data2 >>> 32);
+ myCanReEnumerate = myEnumerator.canReEnumerate();
+
+ if (makesSenseToCompact()) {
+ compact();
+ }
+ }
+ catch (IOException e) {
+ try {
+ // attempt to close already opened resources
+ close();
+ }
+ catch (Throwable ignored) {
+ }
+ throw e; // rethrow
+ }
+ catch (Throwable t) {
+ LOG.error(t);
+ try {
+ // attempt to close already opened resources
+ close();
+ }
+ catch (Throwable ignored) {
+ }
+ throw new PersistentEnumerator.CorruptedException(file);
+ }
+ }
+
+ private static int modifyVersionDependingOnOptions(int version, @NotNull PersistentHashMapValueStorage.CreationTimeOptions options) {
+ return version + options.getVersion();
+ }
+
+ protected boolean wantNonNegativeIntegralValues() {
+ return false;
+ }
+
+ protected boolean isReadOnly() {
+ return false;
+ }
+
+ private static final int MAX_RECYCLED_BUFFER_SIZE = 4096;
+
+ private SLRUCache<Key, BufferExposingByteArrayOutputStream> createAppendCache(final KeyDescriptor<Key> keyDescriptor) {
+ return new SLRUCache<Key, BufferExposingByteArrayOutputStream>(16 * 1024, 4 * 1024, keyDescriptor) {
+ @Override
+ @NotNull
+ public BufferExposingByteArrayOutputStream createValue(final Key key) {
+ return myStreamPool.alloc();
+ }
+
+ @Override
+ protected void onDropFromCache(final Key key, @NotNull final BufferExposingByteArrayOutputStream bytes) {
+ appendDataWithoutCache(key, bytes);
+ }
+ };
+ }
+
+ private static boolean doNewCompact() {
+ return System.getProperty("idea.persistent.hash.map.oldcompact") == null;
+ }
+
+ private boolean forceNewCompact() {
+ return System.getProperty("idea.persistent.hash.map.newcompact") != null &&
+ (int)(myLiveAndGarbageKeysCounter & DEAD_KEY_NUMBER_MASK) > 0;
+ }
+
+ public final void dropMemoryCaches() {
+ if (myDoTrace) LOG.info("Drop memory caches " + myStorageFile);
+ synchronized (myEnumerator) {
+ doDropMemoryCaches();
+ }
+ }
+
+ protected void doDropMemoryCaches() {
+ myEnumerator.lockStorage();
+ try {
+ clearAppenderCaches();
+ }
+ finally {
+ myEnumerator.unlockStorage();
+ }
+ }
+
+ int getGarbageSize() {
+ return (int)myLiveAndGarbageKeysCounter;
+ }
+
+ public File getBaseFile() {
+ return myEnumerator.myFile;
+ }
+
+ @TestOnly // public for tests
+ @SuppressWarnings("WeakerAccess") // used in upsource for some reason
+ public boolean makesSenseToCompact() {
+ if (myIsReadOnly) return false;
+
+ final long fileSize = myValueStorage.getSize();
+ final int megabyte = 1024 * 1024;
+
+ if (fileSize > 5 * megabyte) { // file is longer than 5MB and (more than 50% of keys is garbage or approximate benefit larger than 100M)
+ int liveKeys = (int)(myLiveAndGarbageKeysCounter / LIVE_KEY_MASK);
+ int deadKeys = (int)(myLiveAndGarbageKeysCounter & DEAD_KEY_NUMBER_MASK);
+
+ if (fileSize > 50 * megabyte && forceNewCompact()) return true;
+ if (deadKeys < 50) return false;
+
+ final long benefitSize = Math.max(100 * megabyte, fileSize / 4);
+ final long avgValueSize = fileSize / (liveKeys + deadKeys);
+
+ return deadKeys > liveKeys ||
+ avgValueSize * deadKeys > benefitSize ||
+ myReadCompactionGarbageSize > fileSize / 2;
+ }
+ return false;
+ }
+
+ @NotNull
+ private static File checkDataFiles(@NotNull final File file) {
+ if (!file.exists()) {
+ deleteFilesStartingWith(getDataFile(file));
+ }
+ return file;
+ }
+
+ public static void deleteFilesStartingWith(@NotNull File prefixFile) {
+ IOUtil.deleteAllFilesStartingWith(prefixFile);
+ }
+
+ @NotNull
+ static File getDataFile(@NotNull final File file) { // made public for testing
+ return new File(file.getParentFile(), file.getName() + DATA_FILE_EXTENSION);
+ }
+
+ @Override
+ public final void put(Key key, Value value) throws IOException {
+ if (myIsReadOnly) throw new IncorrectOperationException();
+ synchronized (myEnumerator) {
+ try {
+ doPut(key, value);
+ }
+ catch (IOException ex) {
+ myEnumerator.markCorrupted();
+ throw ex;
+ }
+ }
+ }
+
+ protected void doPut(Key key, Value value) throws IOException {
+ long newValueOffset = -1;
+
+ if (!myIntMapping) {
+ final BufferExposingByteArrayOutputStream bytes = new BufferExposingByteArrayOutputStream();
+ AppendStream appenderStream = ourFlyweightAppenderStream.getValue();
+ appenderStream.setOut(bytes);
+ myValueExternalizer.save(appenderStream, value);
+ appenderStream.setOut(null);
+ newValueOffset = myValueStorage.appendBytes(bytes.toByteArraySequence(), 0);
+ }
+
+ myEnumerator.lockStorage();
+ try {
+ myEnumerator.markDirty(true);
+ myAppendCache.remove(key);
+
+ long oldValueOffset;
+ if (myDirectlyStoreLongFileOffsetMode) {
+ if (myIntMapping) {
+ ((PersistentBTreeEnumerator<Key>)myEnumerator).putNonNegativeValue(key, (Integer)value);
+ return;
+ }
+ oldValueOffset = ((PersistentBTreeEnumerator<Key>)myEnumerator).getNonNegativeValue(key);
+ ((PersistentBTreeEnumerator<Key>)myEnumerator).putNonNegativeValue(key, newValueOffset);
+ }
+ else {
+ final int id = enumerate(key);
+ if (myIntMapping) {
+ myEnumerator.myStorage.putInt(id + myParentValueRefOffset, (Integer)value);
+ return;
+ }
+
+ oldValueOffset = readValueId(id);
+ updateValueId(id, newValueOffset, oldValueOffset, key, 0);
+ }
+
+ if (oldValueOffset != NULL_ADDR) {
+ myLiveAndGarbageKeysCounter++;
+ }
+ else {
+ myLiveAndGarbageKeysCounter += LIVE_KEY_MASK;
+ }
+ }
+ finally {
+ myEnumerator.unlockStorage();
+ }
+ }
+
+ @Override
+ public final int enumerate(Key name) throws IOException {
+ if (myIsReadOnly) throw new IncorrectOperationException();
+ synchronized (myEnumerator) {
+ myIntAddressForNewRecord = canUseIntAddressForNewRecord(myValueStorage.getSize());
+ return super.enumerate(name);
+ }
+ }
+
+ /**
+ * Appends value chunk from specified appender to key's value.
+ * Important use note: value externalizer used by this map should process all bytes from DataInput during deserialization and make sure
+ * that deserialized value is consistent with value chunks appended.
+ * E.g. Value can be Set of String and individual Strings can be appended with this method for particular key, when {@link #get(Object)} will
+ * be eventually called for the key, deserializer will read all bytes retrieving Strings and collecting them into Set
+ */
+ public final void appendData(Key key, @NotNull PersistentHashMap.ValueDataAppender appender) throws IOException {
+ if (myIsReadOnly) throw new IncorrectOperationException();
+ synchronized (myEnumerator) {
+ try {
+ doAppendData(key, appender);
+ }
+ catch (IOException ex) {
+ myEnumerator.markCorrupted();
+ throw ex;
+ }
+ }
+ }
+
+ public final void appendDataWithoutCache(Key key, Value value) throws IOException {
+ synchronized (myEnumerator) {
+ try {
+ final BufferExposingByteArrayOutputStream bytes = new BufferExposingByteArrayOutputStream();
+ AppendStream appenderStream = ourFlyweightAppenderStream.getValue();
+ appenderStream.setOut(bytes);
+ myValueExternalizer.save(appenderStream, value);
+ appenderStream.setOut(null);
+ appendDataWithoutCache(key, bytes);
+ }
+ catch (IOException ex) {
+ markCorrupted();
+ throw ex;
+ }
+ }
+ }
+
+ private void appendDataWithoutCache(Key key, @NotNull final BufferExposingByteArrayOutputStream bytes) {
+ myEnumerator.lockStorage();
+ try {
+ long previousRecord;
+ final int id;
+ if (myDirectlyStoreLongFileOffsetMode) {
+ previousRecord = ((PersistentBTreeEnumerator<Key>)myEnumerator).getNonNegativeValue(key);
+ id = -1;
+ }
+ else {
+ id = enumerate(key);
+ previousRecord = readValueId(id);
+ }
+
+ long headerRecord = myValueStorage.appendBytes(bytes.toByteArraySequence(), previousRecord);
+
+ if (myDirectlyStoreLongFileOffsetMode) {
+ ((PersistentBTreeEnumerator<Key>)myEnumerator).putNonNegativeValue(key, headerRecord);
+ }
+ else {
+ updateValueId(id, headerRecord, previousRecord, key, 0);
+ }
+
+ if (previousRecord == NULL_ADDR) {
+ myLiveAndGarbageKeysCounter += LIVE_KEY_MASK;
+ }
+
+ if (bytes.getInternalBuffer().length <= MAX_RECYCLED_BUFFER_SIZE) {
+ // Avoid internal fragmentation by not retaining / reusing large append buffers (IDEA-208533)
+ myStreamPool.recycle(bytes);
+ }
+ }
+ catch (IOException e) {
+ markCorrupted();
+ throw new RuntimeException(e);
+ }
+ finally {
+ myEnumerator.unlockStorage();
+ }
+ }
+
+ private static final ThreadLocalCachedValue<AppendStream> ourFlyweightAppenderStream = new ThreadLocalCachedValue<AppendStream>() {
+ @NotNull
+ @Override
+ protected AppendStream create() {
+ return new AppendStream();
+ }
+ };
+
+ private void doAppendData(Key key, @NotNull PersistentHashMap.ValueDataAppender appender) throws IOException {
+ assert !myIntMapping;
+ myEnumerator.markDirty(true);
+
+ AppendStream appenderStream = ourFlyweightAppenderStream.getValue();
+ BufferExposingByteArrayOutputStream stream = myAppendCache.get(key);
+ appenderStream.setOut(stream);
+ myValueStorage.checkAppendsAllowed(stream.size());
+ appender.append(appenderStream);
+ appenderStream.setOut(null);
+ }
+
+ /**
+ * Process all keys registered in the map. Note that keys which were removed after {@link #compact()} call will be processed as well. Use
+ * {@link #processKeysWithExistingMapping(Processor)} to process only keys with existing mappings
+ */
+ @Override
+ public final boolean processKeys(@NotNull Processor<? super Key> processor) throws IOException {
+ synchronized (myEnumerator) {
+ try {
+ myAppendCache.clear();
+ return myEnumerator.iterateData(processor);
+ }
+ catch (IOException e) {
+ myEnumerator.markCorrupted();
+ throw e;
+ }
+ }
+ }
+
+ @NotNull
+ public Collection<Key> getAllKeysWithExistingMapping() throws IOException {
+ final List<Key> values = new ArrayList<>();
+ processKeysWithExistingMapping(new CommonProcessors.CollectProcessor<>(values));
+ return values;
+ }
+
+ public final boolean processKeysWithExistingMapping(Processor<? super Key> processor) throws IOException {
+ synchronized (myEnumerator) {
+ try {
+ myAppendCache.clear();
+ return myEnumerator.processAllDataObject(processor, new PersistentEnumerator.DataFilter() {
+ @Override
+ public boolean accept(final int id) {
+ return readValueId(id) != NULL_ADDR;
+ }
+ });
+ }
+ catch (IOException e) {
+ myEnumerator.markCorrupted();
+ throw e;
+ }
+ }
+ }
+
+ @Override
+ public final Value get(Key key) throws IOException {
+ synchronized (myEnumerator) {
+ myBusyReading = true;
+ try {
+ return doGet(key);
+ }
+ catch (IOException ex) {
+ myEnumerator.markCorrupted();
+ throw ex;
+ }
+ finally {
+ myBusyReading = false;
+ }
+ }
+ }
+
+ public boolean isBusyReading() {
+ return myBusyReading;
+ }
+
+ @Nullable
+ protected Value doGet(Key key) throws IOException {
+ myEnumerator.lockStorage();
+ final long valueOffset;
+ final int id;
+ try {
+ myAppendCache.remove(key);
+
+ if (myDirectlyStoreLongFileOffsetMode) {
+ valueOffset = ((PersistentBTreeEnumerator<Key>)myEnumerator).getNonNegativeValue(key);
+ if (myIntMapping) {
+ return (Value)(Integer)(int)valueOffset;
+ }
+ id = -1;
+ }
+ else {
+ id = tryEnumerate(key);
+ if (id == PersistentEnumeratorBase.NULL_ID) {
+ return null;
+ }
+
+ if (myIntMapping) {
+ return (Value)(Integer)myEnumerator.myStorage.getInt(id + myParentValueRefOffset);
+ }
+
+ valueOffset = readValueId(id);
+ }
+
+ if (valueOffset == NULL_ADDR) {
+ return null;
+ }
+ }
+ finally {
+ myEnumerator.unlockStorage();
+ }
+
+ final PersistentHashMapValueStorage.ReadResult readResult = myValueStorage.readBytes(valueOffset);
+
+ final Value valueRead;
+ try (DataInputStream input = new DataInputStream(new UnsyncByteArrayInputStream(readResult.buffer))) {
+ valueRead = myValueExternalizer.read(input);
+ }
+
+ if (myValueStorage.performChunksCompaction(readResult.chunksCount, readResult.buffer.length)) {
+
+ long newValueOffset = myValueStorage.compactChunks(new PersistentHashMap.ValueDataAppender() {
+ @Override
+ public void append(DataOutput out) throws IOException {
+ myValueExternalizer.save(out, valueRead);
+ }
+ }, readResult);
+
+ myEnumerator.lockStorage();
+ try {
+ myEnumerator.markDirty(true);
+
+ if (myDirectlyStoreLongFileOffsetMode) {
+ ((PersistentBTreeEnumerator<Key>)myEnumerator).putNonNegativeValue(key, newValueOffset);
+ }
+ else {
+ updateValueId(id, newValueOffset, valueOffset, key, 0);
+ }
+ myLiveAndGarbageKeysCounter++;
+ myReadCompactionGarbageSize += readResult.buffer.length;
+ }
+ finally {
+ myEnumerator.unlockStorage();
+ }
+ }
+ return valueRead;
+ }
+
+ public final boolean containsMapping(Key key) throws IOException {
+ synchronized (myEnumerator) {
+ return doContainsMapping(key);
+ }
+ }
+
+ private boolean doContainsMapping(Key key) throws IOException {
+ myEnumerator.lockStorage();
+ try {
+ myAppendCache.remove(key);
+ if (myDirectlyStoreLongFileOffsetMode) {
+ return ((PersistentBTreeEnumerator<Key>)myEnumerator).getNonNegativeValue(key) != NULL_ADDR;
+ }
+ else {
+ final int id = tryEnumerate(key);
+ if (id == PersistentEnumeratorBase.NULL_ID) {
+ return false;
+ }
+ if (myIntMapping) return true;
+ return readValueId(id) != NULL_ADDR;
+ }
+ }
+ finally {
+ myEnumerator.unlockStorage();
+ }
+ }
+
+ public final void remove(Key key) throws IOException {
+ if (myIsReadOnly) throw new IncorrectOperationException();
+ synchronized (myEnumerator) {
+ doRemove(key);
+ }
+ }
+
+ protected void doRemove(Key key) throws IOException {
+ myEnumerator.lockStorage();
+ try {
+
+ myAppendCache.remove(key);
+ final long record;
+ if (myDirectlyStoreLongFileOffsetMode) {
+ assert !myIntMapping; // removal isn't supported
+ record = ((PersistentBTreeEnumerator<Key>)myEnumerator).getNonNegativeValue(key);
+ if (record != NULL_ADDR) {
+ ((PersistentBTreeEnumerator<Key>)myEnumerator).putNonNegativeValue(key, NULL_ADDR);
+ }
+ }
+ else {
+ final int id = tryEnumerate(key);
+ if (id == PersistentEnumeratorBase.NULL_ID) {
+ return;
+ }
+ assert !myIntMapping; // removal isn't supported
+ myEnumerator.markDirty(true);
+
+ record = readValueId(id);
+ updateValueId(id, NULL_ADDR, record, key, 0);
+ }
+ if (record != NULL_ADDR) {
+ myLiveAndGarbageKeysCounter++;
+ myLiveAndGarbageKeysCounter -= LIVE_KEY_MASK;
+ }
+ }
+ finally {
+ myEnumerator.unlockStorage();
+ }
+ }
+
+ @Override
+ public final void force() {
+ if (myIsReadOnly) return;
+ if (myDoTrace) LOG.info("Forcing " + myStorageFile);
+ synchronized (myEnumerator) {
+ doForce();
+ }
+ }
+
+ protected void doForce() {
+ myEnumerator.lockStorage();
+ try {
+ try {
+ clearAppenderCaches();
+ }
+ finally {
+ super.force();
+ }
+ }
+ finally {
+ myEnumerator.unlockStorage();
+ }
+ }
+
+ private void clearAppenderCaches() {
+ myAppendCache.clear();
+ myValueStorage.force();
+ }
+
+ @Override
+ public final void close() throws IOException {
+ if (myDoTrace) LOG.info("Closed " + myStorageFile);
+ synchronized (myEnumerator) {
+ doClose();
+ }
+ }
+
+ private void doClose() throws IOException {
+ myEnumerator.lockStorage();
+ try {
+ try {
+ myAppendCacheFlusher.stop();
+ try {
+ myAppendCache.clear();
+ }
+ catch (RuntimeException ex) {
+ Throwable cause = ex.getCause();
+ if (cause instanceof IOException) throw (IOException)cause;
+ throw ex;
+ }
+ }
+ finally {
+ final PersistentHashMapValueStorage valueStorage = myValueStorage;
+ try {
+ if (valueStorage != null) {
+ valueStorage.dispose();
+ }
+ }
+ finally {
+ super.close();
+ }
+ }
+ }
+ finally {
+ myEnumerator.unlockStorage();
+ }
+ }
+
+ //static class CompactionRecordInfo {
+ // final int key;
+ // final int address;
+ // long valueAddress;
+ // long newValueAddress;
+ // byte[] value;
+ //
+ // CompactionRecordInfo(int _key, long _valueAddress, int _address) {
+ // key = _key;
+ // address = _address;
+ // valueAddress = _valueAddress;
+ // }
+ //}
+
+ // made public for tests
+ public void compact() throws IOException {
+ if (myIsReadOnly) throw new IncorrectOperationException();
+ synchronized (myEnumerator) {
+ force();
+ LOG.info("Compacting " + myEnumerator.myFile.getPath());
+ LOG.info("Live keys:" + (int)(myLiveAndGarbageKeysCounter / LIVE_KEY_MASK) +
+ ", dead keys:" + (int)(myLiveAndGarbageKeysCounter & DEAD_KEY_NUMBER_MASK) +
+ ", read compaction size:" + myReadCompactionGarbageSize);
+
+ final long now = System.currentTimeMillis();
+
+ final File oldDataFile = getDataFile(myEnumerator.myFile);
+ final String oldDataFileBaseName = oldDataFile.getName();
+ final File[] oldFiles = getFilesInDirectoryWithNameStartingWith(oldDataFile, oldDataFileBaseName);
+
+ final String newPath = getDataFile(myEnumerator.myFile).getPath() + ".new";
+ PersistentHashMapValueStorage.CreationTimeOptions options = myValueStorage.getOptions();
+ final PersistentHashMapValueStorage newStorage = PersistentHashMapValueStorage.create(newPath, options);
+ myValueStorage.switchToCompactionMode();
+ myEnumerator.markDirty(true);
+ long sizeBefore = myValueStorage.getSize();
+
+ myLiveAndGarbageKeysCounter = 0;
+ myReadCompactionGarbageSize = 0;
+
+ try {
+ if (doNewCompact()) {
+ newCompact(newStorage);
+ }
+ else {
+ traverseAllRecords(new PersistentEnumerator.RecordsProcessor() {
+ @Override
+ public boolean process(final int keyId) throws IOException {
+ final long record = readValueId(keyId);
+ if (record != NULL_ADDR) {
+ PersistentHashMapValueStorage.ReadResult readResult = myValueStorage.readBytes(record);
+ long value = newStorage.appendBytes(readResult.buffer, 0, readResult.buffer.length, 0);
+ updateValueId(keyId, value, record, null, getCurrentKey());
+ myLiveAndGarbageKeysCounter += LIVE_KEY_MASK;
+ }
+ return true;
+ }
+ });
+ }
+ }
+ finally {
+ newStorage.dispose();
+ }
+
+ myValueStorage.dispose();
+
+ if (oldFiles != null) {
+ for (File f : oldFiles) {
+ assert FileUtil.deleteWithRenaming(f);
+ }
+ }
+
+ final long newSize = newStorage.getSize();
+
+ File newDataFile = new File(newPath);
+ final String newBaseName = newDataFile.getName();
+ final File[] newFiles = getFilesInDirectoryWithNameStartingWith(newDataFile, newBaseName);
+
+ if (newFiles != null) {
+ File parentFile = newDataFile.getParentFile();
+
+ // newFiles should get the same names as oldDataFiles
+ for (File f : newFiles) {
+ String nameAfterRename = StringUtil.replace(f.getName(), newBaseName, oldDataFileBaseName);
+ FileUtil.rename(f, new File(parentFile, nameAfterRename));
+ }
+ }
+
+ myValueStorage = PersistentHashMapValueStorage.create(oldDataFile.getPath(), options);
+ LOG.info("Compacted " + myEnumerator.myFile.getPath() + ":" + sizeBefore + " bytes into " +
+ newSize + " bytes in " + (System.currentTimeMillis() - now) + "ms.");
+ myEnumerator.putMetaData(myLiveAndGarbageKeysCounter);
+ myEnumerator.putMetaData2(myLargeIndexWatermarkId);
+ if (myDoTrace) LOG.assertTrue(myEnumerator.isDirty());
+ }
+ }
+
+ private static File[] getFilesInDirectoryWithNameStartingWith(@NotNull File fileFromDirectory, @NotNull final String baseFileName) {
+ File parentFile = fileFromDirectory.getParentFile();
+ return parentFile != null ? parentFile.listFiles(pathname -> pathname.getName().startsWith(baseFileName)) : null;
+ }
+
+ private void newCompact(@NotNull PersistentHashMapValueStorage newStorage) throws IOException {
+ long started = System.currentTimeMillis();
+ final List<PersistentHashMap.CompactionRecordInfo> infos = new ArrayList<>(10000);
+
+ traverseAllRecords(new PersistentEnumerator.RecordsProcessor() {
+ @Override
+ public boolean process(final int keyId) {
+ final long record = readValueId(keyId);
+ if (record != NULL_ADDR) {
+ infos.add(new PersistentHashMap.CompactionRecordInfo(getCurrentKey(), record, keyId));
+ }
+ return true;
+ }
+ });
+
+ LOG.info("Loaded mappings:" + (System.currentTimeMillis() - started) + "ms, keys:" + infos.size());
+ started = System.currentTimeMillis();
+ long fragments = 0;
+ if (!infos.isEmpty()) {
+ try {
+ fragments = myValueStorage.compactValues(infos, newStorage);
+ }
+ catch (Throwable t) {
+ if (!(t instanceof IOException)) throw new IOException("Compaction failed", t);
+ throw (IOException)t;
+ }
+ }
+
+ LOG.info("Compacted values for:" + (System.currentTimeMillis() - started) + "ms fragments:" +
+ (int)fragments + ", new fragments:" + (fragments >> 32));
+
+ started = System.currentTimeMillis();
+ try {
+ myEnumerator.lockStorage();
+
+ for (PersistentHashMap.CompactionRecordInfo info : infos) {
+ updateValueId(info.address, info.newValueAddress, info.valueAddress, null, info.key);
+ myLiveAndGarbageKeysCounter += LIVE_KEY_MASK;
+ }
+ }
+ finally {
+ myEnumerator.unlockStorage();
+ }
+ LOG.info("Updated mappings:" + (System.currentTimeMillis() - started) + " ms");
+ }
+
+ private long readValueId(final int keyId) {
+ if (myDirectlyStoreLongFileOffsetMode) {
+ return ((PersistentBTreeEnumerator<Key>)myEnumerator).keyIdToNonNegativeOffset(keyId);
+ }
+ long address = myEnumerator.myStorage.getInt(keyId + myParentValueRefOffset);
+ if (address == 0 || address == -POSITIVE_VALUE_SHIFT) {
+ return NULL_ADDR;
+ }
+
+ if (address < 0) {
+ address = -address - POSITIVE_VALUE_SHIFT;
+ }
+ else {
+ long value = myEnumerator.myStorage.getInt(keyId + myParentValueRefOffset + 4) & 0xFFFFFFFFL;
+ address = ((address << 32) + value) & ~USED_LONG_VALUE_MASK;
+ }
+
+ return address;
+ }
+
+ private int smallKeys;
+ private int largeKeys;
+ private int transformedKeys;
+ private int requests;
+
+ private int updateValueId(int keyId, long value, long oldValue, @Nullable Key key, int processingKey) throws IOException {
+ if (myDirectlyStoreLongFileOffsetMode) {
+ ((PersistentBTreeEnumerator<Key>)myEnumerator).putNonNegativeValue(((InlineKeyDescriptor<Key>)myKeyDescriptor).fromInt(processingKey), value);
+ return keyId;
+ }
+ final boolean newKey = oldValue == NULL_ADDR;
+ if (newKey) ++requests;
+ boolean defaultSizeInfo = true;
+
+ if (myCanReEnumerate) {
+ if (canUseIntAddressForNewRecord(value)) {
+ defaultSizeInfo = false;
+ myEnumerator.myStorage.putInt(keyId + myParentValueRefOffset, -(int)(value + POSITIVE_VALUE_SHIFT));
+ if (newKey) ++smallKeys;
+ }
+ else if ((keyId < myLargeIndexWatermarkId || myLargeIndexWatermarkId == 0) && (newKey || canUseIntAddressForNewRecord(oldValue))) {
+ // keyId is result of enumerate, if we do re-enumerate then it is no longer accessible unless somebody cached it
+ myIntAddressForNewRecord = false;
+ keyId = myEnumerator.reEnumerate(key == null ? myEnumerator.getValue(keyId, processingKey) : key);
+ ++transformedKeys;
+ if (myLargeIndexWatermarkId == 0) {
+ myLargeIndexWatermarkId = keyId;
+ }
+ }
+ }
+
+ if (defaultSizeInfo) {
+ value |= USED_LONG_VALUE_MASK;
+
+ myEnumerator.myStorage.putInt(keyId + myParentValueRefOffset, (int)(value >>> 32));
+ myEnumerator.myStorage.putInt(keyId + myParentValueRefOffset + 4, (int)value);
+
+ if (newKey) ++largeKeys;
+ }
+
+ if (newKey && IOStatistics.DEBUG && (requests & IOStatistics.KEYS_FACTOR_MASK) == 0) {
+ IOStatistics.dump("small:" + smallKeys + ", large:" + largeKeys + ", transformed:" + transformedKeys +
+ ",@" + getBaseFile().getPath());
+ }
+ if (doHardConsistencyChecks) {
+ long checkRecord = readValueId(keyId);
+ assert checkRecord == (value & ~USED_LONG_VALUE_MASK) : value;
+ }
+ return keyId;
+ }
+
+ @Override
+ public String toString() {
+ return super.toString() + ": " + myStorageFile;
+ }
+
+ @TestOnly
+ PersistentHashMapValueStorage getValueStorage() {
+ return myValueStorage;
+ }
+
+ @TestOnly
+ public boolean getReadOnly() {
+ return myIsReadOnly;
+ }
+}
diff --git a/build-common/src/org/jetbrains/kotlin/incremental/storage/NonCachingLazyStorage.kt b/build-common/src/org/jetbrains/kotlin/incremental/storage/NonCachingLazyStorage.kt
index 7cfcb00..9a87729 100644
--- a/build-common/src/org/jetbrains/kotlin/incremental/storage/NonCachingLazyStorage.kt
+++ b/build-common/src/org/jetbrains/kotlin/incremental/storage/NonCachingLazyStorage.kt
@@ -1,106 +1,106 @@
-/*
- * Copyright 2010-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 org.jetbrains.kotlin.incremental.storage
-
-import com.intellij.util.io.DataExternalizer
-import com.intellij.util.io.KeyDescriptor
-import com.intellij.util.io.JpsPersistentHashMap
-import java.io.File
-
-
-class NonCachingLazyStorage<K, V>(
- private val storageFile: File,
- private val keyDescriptor: KeyDescriptor<K>,
- private val valueExternalizer: DataExternalizer<V>
-) : LazyStorage<K, V> {
- @Volatile
- private var storage: JpsPersistentHashMap<K, V>? = null
-
- @Synchronized
- private fun getStorageIfExists(): JpsPersistentHashMap<K, V>? {
- if (storage != null) return storage
-
- if (storageFile.exists()) {
- storage = createMap()
- return storage
- }
-
- return null
- }
-
- @Synchronized
- private fun getStorageOrCreateNew(): JpsPersistentHashMap<K, V> {
- if (storage == null) {
- storage = createMap()
- }
-
- return storage!!
- }
-
- override val keys: Collection<K>
- get() = getStorageIfExists()?.allKeysWithExistingMapping ?: listOf()
-
- override operator fun contains(key: K): Boolean =
- getStorageIfExists()?.containsMapping(key) ?: false
-
- override operator fun get(key: K): V? =
- getStorageIfExists()?.get(key)
-
- override operator fun set(key: K, value: V) {
- getStorageOrCreateNew().put(key, value)
- }
-
- override fun remove(key: K) {
- getStorageIfExists()?.remove(key)
- }
-
- override fun append(key: K, value: V) {
- getStorageOrCreateNew().appendDataWithoutCache(key, value)
- }
-
- @Synchronized
- override fun clean() {
- try {
- storage?.close()
- } catch (ignored: Throwable) {
- }
-
- JpsPersistentHashMap.deleteFilesStartingWith(storageFile)
- storage = null
- }
-
- @Synchronized
- override fun flush(memoryCachesOnly: Boolean) {
- val existingStorage = storage ?: return
-
- if (memoryCachesOnly) {
- if (existingStorage.isDirty) {
- existingStorage.dropMemoryCaches()
- }
- } else {
- existingStorage.force()
- }
- }
-
- @Synchronized
- override fun close() {
- storage?.close()
- }
-
- private fun createMap(): JpsPersistentHashMap<K, V> =
- JpsPersistentHashMap(storageFile, keyDescriptor, valueExternalizer)
-}
+/*
+ * Copyright 2010-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 org.jetbrains.kotlin.incremental.storage
+
+import com.intellij.util.io.DataExternalizer
+import com.intellij.util.io.KeyDescriptor
+import com.intellij.util.io.PersistentHashMap
+import java.io.File
+
+
+class NonCachingLazyStorage<K, V>(
+ private val storageFile: File,
+ private val keyDescriptor: KeyDescriptor<K>,
+ private val valueExternalizer: DataExternalizer<V>
+) : LazyStorage<K, V> {
+ @Volatile
+ private var storage: PersistentHashMap<K, V>? = null
+
+ @Synchronized
+ private fun getStorageIfExists(): PersistentHashMap<K, V>? {
+ if (storage != null) return storage
+
+ if (storageFile.exists()) {
+ storage = createMap()
+ return storage
+ }
+
+ return null
+ }
+
+ @Synchronized
+ private fun getStorageOrCreateNew(): PersistentHashMap<K, V> {
+ if (storage == null) {
+ storage = createMap()
+ }
+
+ return storage!!
+ }
+
+ override val keys: Collection<K>
+ get() = getStorageIfExists()?.allKeysWithExistingMapping ?: listOf()
+
+ override operator fun contains(key: K): Boolean =
+ getStorageIfExists()?.containsMapping(key) ?: false
+
+ override operator fun get(key: K): V? =
+ getStorageIfExists()?.get(key)
+
+ override operator fun set(key: K, value: V) {
+ getStorageOrCreateNew().put(key, value)
+ }
+
+ override fun remove(key: K) {
+ getStorageIfExists()?.remove(key)
+ }
+
+ override fun append(key: K, value: V) {
+ getStorageOrCreateNew().appendData(key) { dataOutput -> valueExternalizer.save(dataOutput, value) }
+ }
+
+ @Synchronized
+ override fun clean() {
+ try {
+ storage?.close()
+ } catch (ignored: Throwable) {
+ }
+
+ PersistentHashMap.deleteFilesStartingWith(storageFile)
+ storage = null
+ }
+
+ @Synchronized
+ override fun flush(memoryCachesOnly: Boolean) {
+ val existingStorage = storage ?: return
+
+ if (memoryCachesOnly) {
+ if (existingStorage.isDirty) {
+ existingStorage.dropMemoryCaches()
+ }
+ } else {
+ existingStorage.force()
+ }
+ }
+
+ @Synchronized
+ override fun close() {
+ storage?.close()
+ }
+
+ private fun createMap(): PersistentHashMap<K, V> =
+ PersistentHashMap(storageFile, keyDescriptor, valueExternalizer)
+}
diff --git a/build-common/src/org/jetbrains/kotlin/incremental/storage/NonCachingLazyStorage.kt.193 b/build-common/src/org/jetbrains/kotlin/incremental/storage/NonCachingLazyStorage.kt.193
new file mode 100644
index 0000000..2d36bda
--- /dev/null
+++ b/build-common/src/org/jetbrains/kotlin/incremental/storage/NonCachingLazyStorage.kt.193
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2010-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 org.jetbrains.kotlin.incremental.storage
+
+import com.intellij.util.io.DataExternalizer
+import com.intellij.util.io.KeyDescriptor
+import com.intellij.util.io.JpsPersistentHashMap
+import java.io.File
+
+
+class NonCachingLazyStorage<K, V>(
+ private val storageFile: File,
+ private val keyDescriptor: KeyDescriptor<K>,
+ private val valueExternalizer: DataExternalizer<V>
+) : LazyStorage<K, V> {
+ @Volatile
+ private var storage: JpsPersistentHashMap<K, V>? = null
+
+ @Synchronized
+ private fun getStorageIfExists(): JpsPersistentHashMap<K, V>? {
+ if (storage != null) return storage
+
+ if (storageFile.exists()) {
+ storage = createMap()
+ return storage
+ }
+
+ return null
+ }
+
+ @Synchronized
+ private fun getStorageOrCreateNew(): JpsPersistentHashMap<K, V> {
+ if (storage == null) {
+ storage = createMap()
+ }
+
+ return storage!!
+ }
+
+ override val keys: Collection<K>
+ get() = getStorageIfExists()?.allKeysWithExistingMapping ?: listOf()
+
+ override operator fun contains(key: K): Boolean =
+ getStorageIfExists()?.containsMapping(key) ?: false
+
+ override operator fun get(key: K): V? =
+ getStorageIfExists()?.get(key)
+
+ override operator fun set(key: K, value: V) {
+ getStorageOrCreateNew().put(key, value)
+ }
+
+ override fun remove(key: K) {
+ getStorageIfExists()?.remove(key)
+ }
+
+ override fun append(key: K, value: V) {
+ getStorageOrCreateNew().appendDataWithoutCache(key, value)
+ }
+
+ @Synchronized
+ override fun clean() {
+ try {
+ storage?.close()
+ } catch (ignored: Throwable) {
+ }
+
+ JpsPersistentHashMap.deleteFilesStartingWith(storageFile)
+ storage = null
+ }
+
+ @Synchronized
+ override fun flush(memoryCachesOnly: Boolean) {
+ val existingStorage = storage ?: return
+
+ if (memoryCachesOnly) {
+ if (existingStorage.isDirty) {
+ existingStorage.dropMemoryCaches()
+ }
+ } else {
+ existingStorage.force()
+ }
+ }
+
+ @Synchronized
+ override fun close() {
+ storage?.close()
+ }
+
+ private fun createMap(): JpsPersistentHashMap<K, V> =
+ JpsPersistentHashMap(storageFile, keyDescriptor, valueExternalizer)
+}
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreApplicationEnvironment.java b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreApplicationEnvironment.java
index f5a5525..93da438 100644
--- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreApplicationEnvironment.java
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreApplicationEnvironment.java
@@ -1,150 +1,55 @@
-/*
- * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
- * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
- */
-package org.jetbrains.kotlin.cli.jvm.compiler;
-
-import com.intellij.codeInsight.ContainerProvider;
-import com.intellij.codeInsight.JavaContainerProvider;
-import com.intellij.codeInsight.folding.JavaCodeFoldingSettings;
-import com.intellij.codeInsight.folding.impl.JavaCodeFoldingSettingsBase;
-import com.intellij.codeInsight.folding.impl.JavaFoldingBuilderBase;
-import com.intellij.codeInsight.runner.JavaMainMethodProvider;
-import com.intellij.core.CoreApplicationEnvironment;
-import com.intellij.core.CoreJavaDirectoryService;
-import com.intellij.core.CorePsiPackageImplementationHelper;
-import com.intellij.ide.highlighter.ArchiveFileType;
-import com.intellij.ide.highlighter.JavaClassFileType;
-import com.intellij.ide.highlighter.JavaFileType;
-import com.intellij.lang.LanguageASTFactory;
-import com.intellij.lang.MetaLanguage;
-import com.intellij.lang.folding.LanguageFolding;
-import com.intellij.lang.java.JavaLanguage;
-import com.intellij.lang.java.JavaParserDefinition;
-import com.intellij.navigation.ItemPresentationProviders;
-import com.intellij.openapi.Disposable;
-import com.intellij.openapi.extensions.Extensions;
-import com.intellij.openapi.extensions.ExtensionsArea;
-import com.intellij.openapi.fileTypes.FileTypeExtensionPoint;
-import com.intellij.openapi.fileTypes.PlainTextFileType;
-import com.intellij.openapi.fileTypes.PlainTextLanguage;
-import com.intellij.openapi.fileTypes.PlainTextParserDefinition;
-import com.intellij.openapi.projectRoots.JavaVersionService;
-import com.intellij.openapi.vfs.VirtualFileSystem;
-import com.intellij.psi.*;
-import com.intellij.psi.augment.PsiAugmentProvider;
-import com.intellij.psi.augment.TypeAnnotationModifier;
-import com.intellij.psi.compiled.ClassFileDecompilers;
-import com.intellij.psi.impl.LanguageConstantExpressionEvaluator;
-import com.intellij.psi.impl.PsiExpressionEvaluator;
-import com.intellij.psi.impl.PsiSubstitutorFactoryImpl;
-import com.intellij.psi.impl.compiled.ClassFileStubBuilder;
-import com.intellij.psi.impl.file.PsiPackageImplementationHelper;
-import com.intellij.psi.impl.search.MethodSuperSearcher;
-import com.intellij.psi.impl.source.tree.JavaASTFactory;
-import com.intellij.psi.impl.source.tree.PlainTextASTFactory;
-import com.intellij.psi.meta.MetaDataContributor;
-import com.intellij.psi.presentation.java.*;
-import com.intellij.psi.search.searches.SuperMethodsSearch;
-import com.intellij.psi.stubs.BinaryFileStubBuilders;
-import com.intellij.util.QueryExecutor;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-import org.jetbrains.kotlin.cli.jvm.modules.CoreJrtFileSystem;
-
-/**
- * adapted from com.intellij.core.JavaCoreApplicationEnvironment
- * TODO: initiate removal original from com.intellij.core since it seems that there are no usages left
- */
-public class KotlinCoreApplicationEnvironment extends CoreApplicationEnvironment {
-
- public static KotlinCoreApplicationEnvironment create(@NotNull Disposable parentDisposable, boolean unitTestMode) {
- return new KotlinCoreApplicationEnvironment(parentDisposable, unitTestMode);
- }
-
- private KotlinCoreApplicationEnvironment(@NotNull Disposable parentDisposable, boolean unitTestMode) {
- super(parentDisposable, unitTestMode);
-
- registerExtensionPoints();
-
- registerExtensions();
- }
-
- private void registerExtensionPoints() {
- ExtensionsArea area = Extensions.getRootArea();
-
- CoreApplicationEnvironment.registerExtensionPoint(area, BinaryFileStubBuilders.EP_NAME, FileTypeExtensionPoint.class);
- CoreApplicationEnvironment.registerExtensionPoint(area, FileContextProvider.EP_NAME, FileContextProvider.class);
-
- CoreApplicationEnvironment.registerExtensionPoint(area, MetaDataContributor.EP_NAME, MetaDataContributor.class);
- CoreApplicationEnvironment.registerExtensionPoint(area, PsiAugmentProvider.EP_NAME, PsiAugmentProvider.class);
- CoreApplicationEnvironment.registerExtensionPoint(area, JavaMainMethodProvider.EP_NAME, JavaMainMethodProvider.class);
-
- CoreApplicationEnvironment.registerExtensionPoint(area, ContainerProvider.EP_NAME, ContainerProvider.class);
- CoreApplicationEnvironment.registerExtensionPoint(area, ClassFileDecompilers.EP_NAME, ClassFileDecompilers.Decompiler.class);
-
- CoreApplicationEnvironment.registerExtensionPoint(area, TypeAnnotationModifier.EP_NAME, TypeAnnotationModifier.class);
- CoreApplicationEnvironment.registerExtensionPoint(area, MetaLanguage.EP_NAME, MetaLanguage.class);
-
- IdeaExtensionPoints.INSTANCE.registerVersionSpecificAppExtensionPoints(area);
- }
-
- private void registerExtensions() {
- registerFileType(JavaClassFileType.INSTANCE, "class");
- registerFileType(JavaFileType.INSTANCE, "java");
- registerFileType(ArchiveFileType.INSTANCE, "jar;zip");
- registerFileType(PlainTextFileType.INSTANCE, "txt;sh;bat;cmd;policy;log;cgi;MF;jad;jam;htaccess");
-
- addExplicitExtension(LanguageASTFactory.INSTANCE, PlainTextLanguage.INSTANCE, new PlainTextASTFactory());
- registerParserDefinition(new PlainTextParserDefinition());
-
- addExplicitExtension(FileTypeFileViewProviders.INSTANCE, JavaClassFileType.INSTANCE, new ClassFileViewProviderFactory());
- addExplicitExtension(BinaryFileStubBuilders.INSTANCE, JavaClassFileType.INSTANCE, new ClassFileStubBuilder());
-
- addExplicitExtension(LanguageASTFactory.INSTANCE, JavaLanguage.INSTANCE, new JavaASTFactory());
- registerParserDefinition(new JavaParserDefinition());
- addExplicitExtension(LanguageConstantExpressionEvaluator.INSTANCE, JavaLanguage.INSTANCE, new PsiExpressionEvaluator());
-
- addExtension(ContainerProvider.EP_NAME, new JavaContainerProvider());
-
- myApplication.registerService(PsiPackageImplementationHelper.class, new CorePsiPackageImplementationHelper());
- myApplication.registerService(PsiSubstitutorFactory.class, new PsiSubstitutorFactoryImpl());
-
- myApplication.registerService(JavaDirectoryService.class, createJavaDirectoryService());
- myApplication.registerService(JavaVersionService.class, new JavaVersionService());
-
- addExplicitExtension(ItemPresentationProviders.INSTANCE, PsiPackage.class, new PackagePresentationProvider());
- addExplicitExtension(ItemPresentationProviders.INSTANCE, PsiClass.class, new ClassPresentationProvider());
- addExplicitExtension(ItemPresentationProviders.INSTANCE, PsiMethod.class, new MethodPresentationProvider());
- addExplicitExtension(ItemPresentationProviders.INSTANCE, PsiField.class, new FieldPresentationProvider());
- addExplicitExtension(ItemPresentationProviders.INSTANCE, PsiLocalVariable.class, new VariablePresentationProvider());
- addExplicitExtension(ItemPresentationProviders.INSTANCE, PsiParameter.class, new VariablePresentationProvider());
-
- registerApplicationService(JavaCodeFoldingSettings.class, new JavaCodeFoldingSettingsBase());
- addExplicitExtension(LanguageFolding.INSTANCE, JavaLanguage.INSTANCE, new JavaFoldingBuilderBase() {
- @Override
- protected boolean shouldShowExplicitLambdaType(@NotNull PsiAnonymousClass anonymousClass, @NotNull PsiNewExpression expression) {
- return false;
- }
-
- @Override
- protected boolean isBelowRightMargin(@NotNull PsiFile file, int lineLength) {
- return false;
- }
- });
-
- registerApplicationExtensionPoint(SuperMethodsSearch.EP_NAME, QueryExecutor.class);
- addExtension(SuperMethodsSearch.EP_NAME, new MethodSuperSearcher());
- }
-
- // overridden in upsource
- protected CoreJavaDirectoryService createJavaDirectoryService() {
- return new CoreJavaDirectoryService();
- }
-
- @Nullable
- @Override
- protected VirtualFileSystem createJrtFileSystem() {
- return new CoreJrtFileSystem();
- }
+/*
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+package org.jetbrains.kotlin.cli.jvm.compiler;
+
+import com.intellij.DynamicBundle;
+import com.intellij.codeInsight.ContainerProvider;
+import com.intellij.codeInsight.runner.JavaMainMethodProvider;
+import com.intellij.core.JavaCoreApplicationEnvironment;
+import com.intellij.lang.MetaLanguage;
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.extensions.Extensions;
+import com.intellij.openapi.vfs.VirtualFileSystem;
+import com.intellij.psi.FileContextProvider;
+import com.intellij.psi.augment.PsiAugmentProvider;
+import com.intellij.psi.compiled.ClassFileDecompilers;
+import com.intellij.psi.meta.MetaDataContributor;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.kotlin.cli.jvm.modules.CoreJrtFileSystem;
+
+public class KotlinCoreApplicationEnvironment extends JavaCoreApplicationEnvironment {
+ public static KotlinCoreApplicationEnvironment create(@NotNull Disposable parentDisposable, boolean unitTestMode) {
+ KotlinCoreApplicationEnvironment environment = new KotlinCoreApplicationEnvironment(parentDisposable, unitTestMode);
+ registerExtensionPoints();
+ return environment;
+ }
+
+ private KotlinCoreApplicationEnvironment(@NotNull Disposable parentDisposable, boolean unitTestMode) {
+ super(parentDisposable, unitTestMode);
+ }
+
+ private static void registerExtensionPoints() {
+ registerApplicationExtensionPoint(DynamicBundle.LanguageBundleEP.EP_NAME, DynamicBundle.LanguageBundleEP.class);
+ registerApplicationExtensionPoint(FileContextProvider.EP_NAME, FileContextProvider.class);
+
+ registerApplicationExtensionPoint(MetaDataContributor.EP_NAME, MetaDataContributor.class);
+ registerApplicationExtensionPoint(PsiAugmentProvider.EP_NAME, PsiAugmentProvider.class);
+ registerApplicationExtensionPoint(JavaMainMethodProvider.EP_NAME, JavaMainMethodProvider.class);
+
+ registerApplicationExtensionPoint(ContainerProvider.EP_NAME, ContainerProvider.class);
+ registerApplicationExtensionPoint(ClassFileDecompilers.EP_NAME, ClassFileDecompilers.Decompiler.class);
+
+ registerApplicationExtensionPoint(MetaLanguage.EP_NAME, MetaLanguage.class);
+
+ IdeaExtensionPoints.INSTANCE.registerVersionSpecificAppExtensionPoints(Extensions.getRootArea());
+ }
+
+ @Nullable
+ @Override
+ protected VirtualFileSystem createJrtFileSystem() {
+ return new CoreJrtFileSystem();
+ }
}
\ No newline at end of file
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreApplicationEnvironment.java.193 b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreApplicationEnvironment.java.193
new file mode 100644
index 0000000..2bb4bf0
--- /dev/null
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreApplicationEnvironment.java.193
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+package org.jetbrains.kotlin.cli.jvm.compiler;
+
+import com.intellij.codeInsight.ContainerProvider;
+import com.intellij.codeInsight.JavaContainerProvider;
+import com.intellij.codeInsight.folding.JavaCodeFoldingSettings;
+import com.intellij.codeInsight.folding.impl.JavaCodeFoldingSettingsBase;
+import com.intellij.codeInsight.folding.impl.JavaFoldingBuilderBase;
+import com.intellij.codeInsight.runner.JavaMainMethodProvider;
+import com.intellij.core.CoreApplicationEnvironment;
+import com.intellij.core.CoreJavaDirectoryService;
+import com.intellij.core.CorePsiPackageImplementationHelper;
+import com.intellij.ide.highlighter.ArchiveFileType;
+import com.intellij.ide.highlighter.JavaClassFileType;
+import com.intellij.ide.highlighter.JavaFileType;
+import com.intellij.lang.LanguageASTFactory;
+import com.intellij.lang.MetaLanguage;
+import com.intellij.lang.folding.LanguageFolding;
+import com.intellij.lang.java.JavaLanguage;
+import com.intellij.lang.java.JavaParserDefinition;
+import com.intellij.navigation.ItemPresentationProviders;
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.extensions.Extensions;
+import com.intellij.openapi.extensions.ExtensionsArea;
+import com.intellij.openapi.fileTypes.FileTypeExtensionPoint;
+import com.intellij.openapi.fileTypes.PlainTextFileType;
+import com.intellij.openapi.fileTypes.PlainTextLanguage;
+import com.intellij.openapi.fileTypes.PlainTextParserDefinition;
+import com.intellij.openapi.projectRoots.JavaVersionService;
+import com.intellij.openapi.vfs.VirtualFileSystem;
+import com.intellij.psi.*;
+import com.intellij.psi.augment.PsiAugmentProvider;
+import com.intellij.psi.augment.TypeAnnotationModifier;
+import com.intellij.psi.compiled.ClassFileDecompilers;
+import com.intellij.psi.impl.LanguageConstantExpressionEvaluator;
+import com.intellij.psi.impl.PsiExpressionEvaluator;
+import com.intellij.psi.impl.PsiSubstitutorFactoryImpl;
+import com.intellij.psi.impl.compiled.ClassFileStubBuilder;
+import com.intellij.psi.impl.file.PsiPackageImplementationHelper;
+import com.intellij.psi.impl.search.MethodSuperSearcher;
+import com.intellij.psi.impl.source.tree.JavaASTFactory;
+import com.intellij.psi.impl.source.tree.PlainTextASTFactory;
+import com.intellij.psi.meta.MetaDataContributor;
+import com.intellij.psi.presentation.java.*;
+import com.intellij.psi.search.searches.SuperMethodsSearch;
+import com.intellij.psi.stubs.BinaryFileStubBuilders;
+import com.intellij.util.QueryExecutor;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.kotlin.cli.jvm.modules.CoreJrtFileSystem;
+
+/**
+ * adapted from com.intellij.core.JavaCoreApplicationEnvironment
+ * TODO: initiate removal original from com.intellij.core since it seems that there are no usages left
+ */
+public class KotlinCoreApplicationEnvironment extends CoreApplicationEnvironment {
+
+ public static KotlinCoreApplicationEnvironment create(@NotNull Disposable parentDisposable, boolean unitTestMode) {
+ return new KotlinCoreApplicationEnvironment(parentDisposable, unitTestMode);
+ }
+
+ private KotlinCoreApplicationEnvironment(@NotNull Disposable parentDisposable, boolean unitTestMode) {
+ super(parentDisposable, unitTestMode);
+
+ registerExtensionPoints();
+
+ registerExtensions();
+ }
+
+ private void registerExtensionPoints() {
+ ExtensionsArea area = Extensions.getRootArea();
+
+ CoreApplicationEnvironment.registerExtensionPoint(area, BinaryFileStubBuilders.EP_NAME, FileTypeExtensionPoint.class);
+ CoreApplicationEnvironment.registerExtensionPoint(area, FileContextProvider.EP_NAME, FileContextProvider.class);
+
+ CoreApplicationEnvironment.registerExtensionPoint(area, MetaDataContributor.EP_NAME, MetaDataContributor.class);
+ CoreApplicationEnvironment.registerExtensionPoint(area, PsiAugmentProvider.EP_NAME, PsiAugmentProvider.class);
+ CoreApplicationEnvironment.registerExtensionPoint(area, JavaMainMethodProvider.EP_NAME, JavaMainMethodProvider.class);
+
+ CoreApplicationEnvironment.registerExtensionPoint(area, ContainerProvider.EP_NAME, ContainerProvider.class);
+ CoreApplicationEnvironment.registerExtensionPoint(area, ClassFileDecompilers.EP_NAME, ClassFileDecompilers.Decompiler.class);
+
+ CoreApplicationEnvironment.registerExtensionPoint(area, TypeAnnotationModifier.EP_NAME, TypeAnnotationModifier.class);
+ CoreApplicationEnvironment.registerExtensionPoint(area, MetaLanguage.EP_NAME, MetaLanguage.class);
+
+ IdeaExtensionPoints.INSTANCE.registerVersionSpecificAppExtensionPoints(area);
+ }
+
+ private void registerExtensions() {
+ registerFileType(JavaClassFileType.INSTANCE, "class");
+ registerFileType(JavaFileType.INSTANCE, "java");
+ registerFileType(ArchiveFileType.INSTANCE, "jar;zip");
+ registerFileType(PlainTextFileType.INSTANCE, "txt;sh;bat;cmd;policy;log;cgi;MF;jad;jam;htaccess");
+
+ addExplicitExtension(LanguageASTFactory.INSTANCE, PlainTextLanguage.INSTANCE, new PlainTextASTFactory());
+ registerParserDefinition(new PlainTextParserDefinition());
+
+ addExplicitExtension(FileTypeFileViewProviders.INSTANCE, JavaClassFileType.INSTANCE, new ClassFileViewProviderFactory());
+ addExplicitExtension(BinaryFileStubBuilders.INSTANCE, JavaClassFileType.INSTANCE, new ClassFileStubBuilder());
+
+ addExplicitExtension(LanguageASTFactory.INSTANCE, JavaLanguage.INSTANCE, new JavaASTFactory());
+ registerParserDefinition(new JavaParserDefinition());
+ addExplicitExtension(LanguageConstantExpressionEvaluator.INSTANCE, JavaLanguage.INSTANCE, new PsiExpressionEvaluator());
+
+ addExtension(ContainerProvider.EP_NAME, new JavaContainerProvider());
+
+ myApplication.registerService(PsiPackageImplementationHelper.class, new CorePsiPackageImplementationHelper());
+ myApplication.registerService(PsiSubstitutorFactory.class, new PsiSubstitutorFactoryImpl());
+
+ myApplication.registerService(JavaDirectoryService.class, createJavaDirectoryService());
+ myApplication.registerService(JavaVersionService.class, new JavaVersionService());
+
+ addExplicitExtension(ItemPresentationProviders.INSTANCE, PsiPackage.class, new PackagePresentationProvider());
+ addExplicitExtension(ItemPresentationProviders.INSTANCE, PsiClass.class, new ClassPresentationProvider());
+ addExplicitExtension(ItemPresentationProviders.INSTANCE, PsiMethod.class, new MethodPresentationProvider());
+ addExplicitExtension(ItemPresentationProviders.INSTANCE, PsiField.class, new FieldPresentationProvider());
+ addExplicitExtension(ItemPresentationProviders.INSTANCE, PsiLocalVariable.class, new VariablePresentationProvider());
+ addExplicitExtension(ItemPresentationProviders.INSTANCE, PsiParameter.class, new VariablePresentationProvider());
+
+ registerApplicationService(JavaCodeFoldingSettings.class, new JavaCodeFoldingSettingsBase());
+ addExplicitExtension(LanguageFolding.INSTANCE, JavaLanguage.INSTANCE, new JavaFoldingBuilderBase() {
+ @Override
+ protected boolean shouldShowExplicitLambdaType(@NotNull PsiAnonymousClass anonymousClass, @NotNull PsiNewExpression expression) {
+ return false;
+ }
+
+ @Override
+ protected boolean isBelowRightMargin(@NotNull PsiFile file, int lineLength) {
+ return false;
+ }
+ });
+
+ registerApplicationExtensionPoint(SuperMethodsSearch.EP_NAME, QueryExecutor.class);
+ addExtension(SuperMethodsSearch.EP_NAME, new MethodSuperSearcher());
+ }
+
+ // overridden in upsource
+ protected CoreJavaDirectoryService createJavaDirectoryService() {
+ return new CoreJavaDirectoryService();
+ }
+
+ @Nullable
+ @Override
+ protected VirtualFileSystem createJrtFileSystem() {
+ return new CoreJrtFileSystem();
+ }
+}
\ No newline at end of file
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/compat.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/compat.kt
index e731677..73fdd5c 100644
--- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/compat.kt
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/compat.kt
@@ -1,9 +1,14 @@
-/*
- * Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
- * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
- */
-
-package org.jetbrains.kotlin.cli.jvm.compiler
-
-fun setupIdeaStandaloneExecution() {
+/*
+ * Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.cli.jvm.compiler
+
+fun setupIdeaStandaloneExecution() {
+ System.getProperties().setProperty("idea.home.path", System.getProperty("java.io.tmpdir"))
+ System.getProperties().setProperty("project.structure.add.tools.jar.to.new.jdk", "false")
+ System.getProperties().setProperty("psi.track.invalidation", "true")
+ System.getProperties().setProperty("psi.incremental.reparse.depth.limit", "1000")
+ System.getProperties().setProperty("ide.hide.excluded.files", "false")
}
\ No newline at end of file
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/compat.kt.193 b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/compat.kt.193
new file mode 100644
index 0000000..ab0b3a8
--- /dev/null
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/compat.kt.193
@@ -0,0 +1,9 @@
+/*
+ * Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.cli.jvm.compiler
+
+fun setupIdeaStandaloneExecution() {
+}
\ No newline at end of file
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/coreApplicationEnvironmentCompat.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/coreApplicationEnvironmentCompat.kt
index f7df51d..3bfcdc7 100644
--- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/coreApplicationEnvironmentCompat.kt
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/coreApplicationEnvironmentCompat.kt
@@ -1,16 +1,18 @@
-/*
- * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
- * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
- */
-
-package org.jetbrains.kotlin.cli.jvm.compiler
-
-import com.intellij.core.CoreApplicationEnvironment
-import com.intellij.openapi.extensions.ExtensionsArea
-import java.io.File
-
-// BUNCH: 193
-fun registerExtensionPointAndExtensionsEx(pluginFile: File, fileName: String, area: ExtensionsArea) {
- @Suppress("MissingRecentApi")
- CoreApplicationEnvironment.registerExtensionPointAndExtensions(pluginFile, fileName, area)
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.cli.jvm.compiler
+
+import com.intellij.core.CoreApplicationEnvironment
+import com.intellij.openapi.extensions.ExtensionsArea
+import java.io.File
+import java.nio.file.FileSystems
+
+// BUNCH: 193
+fun registerExtensionPointAndExtensionsEx(pluginFile: File, fileName: String, area: ExtensionsArea) {
+ val pluginRoot = FileSystems.getDefault().getPath(pluginFile.path)
+ @Suppress("MissingRecentApi")
+ CoreApplicationEnvironment.registerExtensionPointAndExtensions(pluginRoot, fileName, area)
}
\ No newline at end of file
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/coreApplicationEnvironmentCompat.kt.193 b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/coreApplicationEnvironmentCompat.kt.193
new file mode 100644
index 0000000..cc9a65f
--- /dev/null
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/coreApplicationEnvironmentCompat.kt.193
@@ -0,0 +1,16 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.cli.jvm.compiler
+
+import com.intellij.core.CoreApplicationEnvironment
+import com.intellij.openapi.extensions.ExtensionsArea
+import java.io.File
+
+// BUNCH: 193
+fun registerExtensionPointAndExtensionsEx(pluginFile: File, fileName: String, area: ExtensionsArea) {
+ @Suppress("MissingRecentApi")
+ CoreApplicationEnvironment.registerExtensionPointAndExtensions(pluginFile, fileName, area)
+}
\ No newline at end of file
diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/test/testFramework/KtUsefulTestCase.java b/compiler/tests-common/tests/org/jetbrains/kotlin/test/testFramework/KtUsefulTestCase.java
index 4c808df..ce155de 100644
--- a/compiler/tests-common/tests/org/jetbrains/kotlin/test/testFramework/KtUsefulTestCase.java
+++ b/compiler/tests-common/tests/org/jetbrains/kotlin/test/testFramework/KtUsefulTestCase.java
@@ -1,972 +1,1181 @@
-/*
- * Copyright 2010-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 org.jetbrains.kotlin.test.testFramework;
-
-import com.intellij.diagnostic.PerformanceWatcher;
-import com.intellij.openapi.Disposable;
-import com.intellij.openapi.application.Application;
-import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.application.PathManager;
-import com.intellij.openapi.application.impl.ApplicationInfoImpl;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.util.Comparing;
-import com.intellij.openapi.util.Disposer;
-import com.intellij.openapi.util.JDOMUtil;
-import com.intellij.openapi.util.io.FileUtil;
-import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.openapi.vfs.*;
-import com.intellij.psi.codeStyle.CodeStyleSettings;
-import com.intellij.rt.execution.junit.FileComparisonFailure;
-import com.intellij.testFramework.*;
-import com.intellij.testFramework.exceptionCases.AbstractExceptionCase;
-import com.intellij.util.Consumer;
-import com.intellij.util.ReflectionUtil;
-import com.intellij.util.containers.ContainerUtil;
-import com.intellij.util.containers.hash.HashMap;
-import com.intellij.util.lang.CompoundRuntimeException;
-import com.intellij.util.ui.UIUtil;
-import gnu.trove.Equality;
-import gnu.trove.THashSet;
-import junit.framework.AssertionFailedError;
-import junit.framework.TestCase;
-import org.jdom.Element;
-import org.jetbrains.annotations.Contract;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-import org.jetbrains.kotlin.test.IdeaSystemPropertiesForParallelRunConfigurator;
-import org.jetbrains.kotlin.testFramework.MockComponentManagerCreationTracer;
-import org.jetbrains.kotlin.types.AbstractTypeChecker;
-import org.jetbrains.kotlin.types.FlexibleTypeImpl;
-import org.junit.Assert;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.*;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.function.Supplier;
-
-@SuppressWarnings("UseOfSystemOutOrSystemErr")
-public abstract class KtUsefulTestCase extends TestCase {
- public static final boolean IS_UNDER_TEAMCITY = System.getenv("TEAMCITY_VERSION") != null;
- private static final String TEMP_DIR_MARKER = "unitTest_";
- public static final boolean OVERWRITE_TESTDATA = Boolean.getBoolean("idea.tests.overwrite.data");
-
- private static final String ORIGINAL_TEMP_DIR = FileUtil.getTempDirectory();
-
- private static final Map<String, Long> TOTAL_SETUP_COST_MILLIS = new HashMap<>();
- private static final Map<String, Long> TOTAL_TEARDOWN_COST_MILLIS = new HashMap<>();
-
- private Application application;
-
- static {
- IdeaSystemPropertiesForParallelRunConfigurator.setProperties();
- //TODO: investigate and enable
- //IdeaForkJoinWorkerThreadFactory.setupPoisonFactory();
- Logger.setFactory(TestLoggerFactory.class);
- }
-
- @NotNull
- protected final Disposable myTestRootDisposable = new TestDisposable();
-
- private static final String ourPathToKeep = null;
- private final List<String> myPathsToKeep = new ArrayList<>();
-
- private File myTempDir;
-
- static {
- // Radar #5755208: Command line Java applications need a way to launch without a Dock icon.
- System.setProperty("apple.awt.UIElement", "true");
-
- FlexibleTypeImpl.RUN_SLOW_ASSERTIONS = true;
- AbstractTypeChecker.RUN_SLOW_ASSERTIONS = true;
- }
-
- protected boolean shouldContainTempFiles() {
- return true;
- }
-
- @Override
- protected void setUp() throws Exception {
- // -- KOTLIN ADDITIONAL START --
- application = ApplicationManager.getApplication();
-
- if (application != null && application.isDisposed()) {
- MockComponentManagerCreationTracer.diagnoseDisposedButNotClearedApplication(application);
- }
- // -- KOTLIN ADDITIONAL END --
-
- super.setUp();
-
- if (shouldContainTempFiles()) {
- String testName = FileUtil.sanitizeFileName(getTestName(true));
- if (StringUtil.isEmptyOrSpaces(testName)) testName = "";
- testName = new File(testName).getName(); // in case the test name contains file separators
- myTempDir = FileUtil.createTempDirectory(TEMP_DIR_MARKER, testName, false);
- FileUtil.resetCanonicalTempPathCache(myTempDir.getPath());
- }
-
- boolean isStressTest = isStressTest();
- ApplicationInfoImpl.setInStressTest(isStressTest);
- if (isPerformanceTest()) {
- Timings.getStatistics();
- }
-
- // turn off Disposer debugging for performance tests
- Disposer.setDebugMode(!isStressTest);
- }
-
- @Override
- protected void tearDown() throws Exception {
- try {
- // don't use method references here to make stack trace reading easier
- //noinspection Convert2MethodRef
- new RunAll(
- () -> disposeRootDisposable(),
- () -> cleanupSwingDataStructures(),
- () -> cleanupDeleteOnExitHookList(),
- () -> Disposer.setDebugMode(true),
- () -> {
- if (shouldContainTempFiles()) {
- FileUtil.resetCanonicalTempPathCache(ORIGINAL_TEMP_DIR);
- if (hasTmpFilesToKeep()) {
- File[] files = myTempDir.listFiles();
- if (files != null) {
- for (File file : files) {
- if (!shouldKeepTmpFile(file)) {
- FileUtil.delete(file);
- }
- }
- }
- }
- else {
- FileUtil.delete(myTempDir);
- }
- }
- },
- () -> UIUtil.removeLeakingAppleListeners()
- ).run();
- }
- finally {
- super.tearDown();
- // -- KOTLIN ADDITIONAL START --
- TestApplicationUtilKt.resetApplicationToNull(application);
- application = null;
- // -- KOTLIN ADDITIONAL END --
- }
- }
-
- protected final void disposeRootDisposable() {
- Disposer.dispose(getTestRootDisposable());
- }
-
- protected void addTmpFileToKeep(@NotNull File file) {
- myPathsToKeep.add(file.getPath());
- }
-
- private boolean hasTmpFilesToKeep() {
- return ourPathToKeep != null && FileUtil.isAncestor(myTempDir.getPath(), ourPathToKeep, false) || !myPathsToKeep.isEmpty();
- }
-
- private boolean shouldKeepTmpFile(@NotNull File file) {
- String path = file.getPath();
- if (FileUtil.pathsEqual(path, ourPathToKeep)) return true;
- for (String pathToKeep : myPathsToKeep) {
- if (FileUtil.pathsEqual(path, pathToKeep)) return true;
- }
- return false;
- }
-
- private static final Set<String> DELETE_ON_EXIT_HOOK_DOT_FILES;
- private static final Class DELETE_ON_EXIT_HOOK_CLASS;
- static {
- Class<?> aClass;
- try {
- aClass = Class.forName("java.io.DeleteOnExitHook");
- }
- catch (Exception e) {
- throw new RuntimeException(e);
- }
- @SuppressWarnings("unchecked") Set<String> files = ReflectionUtil.getStaticFieldValue(aClass, Set.class, "files");
- DELETE_ON_EXIT_HOOK_CLASS = aClass;
- DELETE_ON_EXIT_HOOK_DOT_FILES = files;
- }
-
- @SuppressWarnings("SynchronizeOnThis")
- private static void cleanupDeleteOnExitHookList() {
- // try to reduce file set retained by java.io.DeleteOnExitHook
- List<String> list;
- synchronized (DELETE_ON_EXIT_HOOK_CLASS) {
- if (DELETE_ON_EXIT_HOOK_DOT_FILES.isEmpty()) return;
- list = new ArrayList<>(DELETE_ON_EXIT_HOOK_DOT_FILES);
- }
- for (int i = list.size() - 1; i >= 0; i--) {
- String path = list.get(i);
- File file = new File(path);
- if (file.delete() || !file.exists()) {
- synchronized (DELETE_ON_EXIT_HOOK_CLASS) {
- DELETE_ON_EXIT_HOOK_DOT_FILES.remove(path);
- }
- }
- }
- }
-
- @SuppressWarnings("ConstantConditions")
- private static void cleanupSwingDataStructures() throws Exception {
- Object manager = ReflectionUtil.getDeclaredMethod(Class.forName("javax.swing.KeyboardManager"), "getCurrentManager").invoke(null);
- Map componentKeyStrokeMap = ReflectionUtil.getField(manager.getClass(), manager, Hashtable.class, "componentKeyStrokeMap");
- componentKeyStrokeMap.clear();
- Map containerMap = ReflectionUtil.getField(manager.getClass(), manager, Hashtable.class, "containerMap");
- containerMap.clear();
- }
-
- @NotNull
- public Disposable getTestRootDisposable() {
- return myTestRootDisposable;
- }
-
- @Override
- protected void runTest() throws Throwable {
- final Throwable[] throwables = new Throwable[1];
-
- AtomicBoolean completed = new AtomicBoolean(false);
- Runnable runnable = () -> {
- try {
- //TestLoggerFactory.onTestStarted();
- super.runTest();
- TestLoggerFactory.onTestFinished(true);
- completed.set(true);
- }
- catch (InvocationTargetException e) {
- TestLoggerFactory.onTestFinished(false);
- e.fillInStackTrace();
- throwables[0] = e.getTargetException();
- }
- catch (IllegalAccessException e) {
- TestLoggerFactory.onTestFinished(false);
- e.fillInStackTrace();
- throwables[0] = e;
- }
- catch (Throwable e) {
- TestLoggerFactory.onTestFinished(false);
- throwables[0] = e;
- }
- };
-
- invokeTestRunnable(runnable);
-
- if (throwables[0] != null) {
- throw throwables[0];
- }
- if (!completed.get()) {
- throw new IllegalStateException("test didn't start");
- }
- }
-
- protected boolean shouldRunTest() {
- return TestFrameworkUtil.canRunTest(getClass());
- }
-
- protected void invokeTestRunnable(@NotNull Runnable runnable) throws Exception {
- //IdeaTestExecutionPolicy policy = IdeaTestExecutionPolicy.current();
- //if (policy != null && !policy.runInDispatchThread()) {
- // runnable.run();
- //}
- //else {
- EdtTestUtilKt.runInEdtAndWait(() -> {
- runnable.run();
- return null;
- });
- //}
- }
-
- private void defaultRunBare() throws Throwable {
- Throwable exception = null;
- try {
- long setupStart = System.nanoTime();
- setUp();
- long setupCost = (System.nanoTime() - setupStart) / 1000000;
- logPerClassCost(setupCost, TOTAL_SETUP_COST_MILLIS);
-
- runTest();
- }
- catch (Throwable running) {
- exception = running;
- }
- finally {
- try {
- long teardownStart = System.nanoTime();
- tearDown();
- long teardownCost = (System.nanoTime() - teardownStart) / 1000000;
- logPerClassCost(teardownCost, TOTAL_TEARDOWN_COST_MILLIS);
- }
- catch (Throwable tearingDown) {
- if (exception == null) exception = tearingDown;
- else exception = new CompoundRuntimeException(Arrays.asList(exception, tearingDown));
- }
- }
- if (exception != null) throw exception;
- }
-
- /**
- * Logs the setup cost grouped by test fixture class (superclass of the current test class).
- *
- * @param cost setup cost in milliseconds
- */
- private void logPerClassCost(long cost, @NotNull Map<String, Long> costMap) {
- Class<?> superclass = getClass().getSuperclass();
- Long oldCost = costMap.get(superclass.getName());
- long newCost = oldCost == null ? cost : oldCost + cost;
- costMap.put(superclass.getName(), newCost);
- }
-
- @SuppressWarnings("UseOfSystemOutOrSystemErr")
- static void logSetupTeardownCosts() {
- System.out.println("Setup costs");
- long totalSetup = 0;
- for (Map.Entry<String, Long> entry : TOTAL_SETUP_COST_MILLIS.entrySet()) {
- System.out.println(String.format(" %s: %d ms", entry.getKey(), entry.getValue()));
- totalSetup += entry.getValue();
- }
- System.out.println("Teardown costs");
- long totalTeardown = 0;
- for (Map.Entry<String, Long> entry : TOTAL_TEARDOWN_COST_MILLIS.entrySet()) {
- System.out.println(String.format(" %s: %d ms", entry.getKey(), entry.getValue()));
- totalTeardown += entry.getValue();
- }
- System.out.println(String.format("Total overhead: setup %d ms, teardown %d ms", totalSetup, totalTeardown));
- System.out.println(String.format("##teamcity[buildStatisticValue key='ideaTests.totalSetupMs' value='%d']", totalSetup));
- System.out.println(String.format("##teamcity[buildStatisticValue key='ideaTests.totalTeardownMs' value='%d']", totalTeardown));
- }
-
- @Override
- public void runBare() throws Throwable {
- if (!shouldRunTest()) return;
-
- if (runInDispatchThread()) {
- TestRunnerUtil.replaceIdeEventQueueSafely();
- com.intellij.testFramework.EdtTestUtil.runInEdtAndWait(this::defaultRunBare);
- }
- else {
- defaultRunBare();
- }
- }
-
- protected boolean runInDispatchThread() {
- //IdeaTestExecutionPolicy policy = IdeaTestExecutionPolicy.current();
- //if (policy != null) {
- // return policy.runInDispatchThread();
- //}
- return true;
- }
-
- @NotNull
- public static String toString(@NotNull Iterable<?> collection) {
- if (!collection.iterator().hasNext()) {
- return "<empty>";
- }
-
- final StringBuilder builder = new StringBuilder();
- for (final Object o : collection) {
- if (o instanceof THashSet) {
- builder.append(new TreeSet<>((THashSet<?>)o));
- }
- else {
- builder.append(o);
- }
- builder.append('\n');
- }
- return builder.toString();
- }
-
- @SafeVarargs
- public static <T> void assertOrderedEquals(@NotNull T[] actual, @NotNull T... expected) {
- assertOrderedEquals(Arrays.asList(actual), expected);
- }
-
- @SafeVarargs
- public static <T> void assertOrderedEquals(@NotNull Iterable<? extends T> actual, @NotNull T... expected) {
- assertOrderedEquals("", actual, expected);
- }
-
- public static void assertOrderedEquals(@NotNull byte[] actual, @NotNull byte[] expected) {
- assertEquals(expected.length, actual.length);
- for (int i = 0; i < actual.length; i++) {
- byte a = actual[i];
- byte e = expected[i];
- assertEquals("not equals at index: "+i, e, a);
- }
- }
-
- public static void assertOrderedEquals(@NotNull int[] actual, @NotNull int[] expected) {
- if (actual.length != expected.length) {
- fail("Expected size: "+expected.length+"; actual: "+actual.length+"\nexpected: "+Arrays.toString(expected)+"\nactual : "+Arrays.toString(actual));
- }
- for (int i = 0; i < actual.length; i++) {
- int a = actual[i];
- int e = expected[i];
- assertEquals("not equals at index: "+i, e, a);
- }
- }
-
- @SafeVarargs
- public static <T> void assertOrderedEquals(@NotNull String errorMsg, @NotNull Iterable<? extends T> actual, @NotNull T... expected) {
- assertOrderedEquals(errorMsg, actual, Arrays.asList(expected));
- }
-
- public static <T> void assertOrderedEquals(@NotNull Iterable<? extends T> actual, @NotNull Iterable<? extends T> expected) {
- assertOrderedEquals("", actual, expected);
- }
-
- public static <T> void assertOrderedEquals(@NotNull String errorMsg,
- @NotNull Iterable<? extends T> actual,
- @NotNull Iterable<? extends T> expected) {
- //noinspection unchecked
- assertOrderedEquals(errorMsg, actual, expected, Equality.CANONICAL);
- }
-
- public static <T> void assertOrderedEquals(@NotNull String errorMsg,
- @NotNull Iterable<? extends T> actual,
- @NotNull Iterable<? extends T> expected,
- @NotNull Equality<? super T> comparator) {
- if (!equals(actual, expected, comparator)) {
- String expectedString = toString(expected);
- String actualString = toString(actual);
- Assert.assertEquals(errorMsg, expectedString, actualString);
- Assert.fail("Warning! 'toString' does not reflect the difference.\nExpected: " + expectedString + "\nActual: " + actualString);
- }
- }
-
- private static <T> boolean equals(@NotNull Iterable<? extends T> a1,
- @NotNull Iterable<? extends T> a2,
- @NotNull Equality<? super T> comparator) {
- Iterator<? extends T> it1 = a1.iterator();
- Iterator<? extends T> it2 = a2.iterator();
- while (it1.hasNext() || it2.hasNext()) {
- if (!it1.hasNext() || !it2.hasNext()) return false;
- if (!comparator.equals(it1.next(), it2.next())) return false;
- }
- return true;
- }
-
- @SafeVarargs
- public static <T> void assertOrderedCollection(@NotNull T[] collection, @NotNull Consumer<T>... checkers) {
- assertOrderedCollection(Arrays.asList(collection), checkers);
- }
-
- /**
- * Checks {@code actual} contains same elements (in {@link #equals(Object)} meaning) as {@code expected} irrespective of their order
- */
- @SafeVarargs
- public static <T> void assertSameElements(@NotNull T[] actual, @NotNull T... expected) {
- assertSameElements(Arrays.asList(actual), expected);
- }
-
- /**
- * Checks {@code actual} contains same elements (in {@link #equals(Object)} meaning) as {@code expected} irrespective of their order
- */
- @SafeVarargs
- public static <T> void assertSameElements(@NotNull Collection<? extends T> actual, @NotNull T... expected) {
- assertSameElements(actual, Arrays.asList(expected));
- }
-
- /**
- * Checks {@code actual} contains same elements (in {@link #equals(Object)} meaning) as {@code expected} irrespective of their order
- */
- public static <T> void assertSameElements(@NotNull Collection<? extends T> actual, @NotNull Collection<? extends T> expected) {
- assertSameElements("", actual, expected);
- }
-
- /**
- * Checks {@code actual} contains same elements (in {@link #equals(Object)} meaning) as {@code expected} irrespective of their order
- */
- public static <T> void assertSameElements(@NotNull String message, @NotNull Collection<? extends T> actual, @NotNull Collection<? extends T> expected) {
- if (actual.size() != expected.size() || !new HashSet<>(expected).equals(new HashSet<T>(actual))) {
- Assert.assertEquals(message, new HashSet<>(expected), new HashSet<T>(actual));
- }
- }
-
- @SafeVarargs
- public static <T> void assertContainsOrdered(@NotNull Collection<? extends T> collection, @NotNull T... expected) {
- assertContainsOrdered(collection, Arrays.asList(expected));
- }
-
- public static <T> void assertContainsOrdered(@NotNull Collection<? extends T> collection, @NotNull Collection<? extends T> expected) {
- ArrayList<T> copy = new ArrayList<>(collection);
- copy.retainAll(expected);
- assertOrderedEquals(toString(collection), copy, expected);
- }
-
- @SafeVarargs
- public static <T> void assertContainsElements(@NotNull Collection<? extends T> collection, @NotNull T... expected) {
- assertContainsElements(collection, Arrays.asList(expected));
- }
-
- public static <T> void assertContainsElements(@NotNull Collection<? extends T> collection, @NotNull Collection<? extends T> expected) {
- ArrayList<T> copy = new ArrayList<>(collection);
- copy.retainAll(expected);
- assertSameElements(toString(collection), copy, expected);
- }
-
- @NotNull
- public static String toString(@NotNull Object[] collection, @NotNull String separator) {
- return toString(Arrays.asList(collection), separator);
- }
-
- @SafeVarargs
- public static <T> void assertDoesntContain(@NotNull Collection<? extends T> collection, @NotNull T... notExpected) {
- assertDoesntContain(collection, Arrays.asList(notExpected));
- }
-
- public static <T> void assertDoesntContain(@NotNull Collection<? extends T> collection, @NotNull Collection<? extends T> notExpected) {
- ArrayList<T> expected = new ArrayList<>(collection);
- expected.removeAll(notExpected);
- assertSameElements(collection, expected);
- }
-
- @NotNull
- public static String toString(@NotNull Collection<?> collection, @NotNull String separator) {
- List<String> list = ContainerUtil.map2List(collection, String::valueOf);
- Collections.sort(list);
- StringBuilder builder = new StringBuilder();
- boolean flag = false;
- for (final String o : list) {
- if (flag) {
- builder.append(separator);
- }
- builder.append(o);
- flag = true;
- }
- return builder.toString();
- }
-
- @SafeVarargs
- public static <T> void assertOrderedCollection(@NotNull Collection<? extends T> collection, @NotNull Consumer<T>... checkers) {
- if (collection.size() != checkers.length) {
- Assert.fail(toString(collection));
- }
- int i = 0;
- for (final T actual : collection) {
- try {
- checkers[i].consume(actual);
- }
- catch (AssertionFailedError e) {
- //noinspection UseOfSystemOutOrSystemErr
- System.out.println(i + ": " + actual);
- throw e;
- }
- i++;
- }
- }
-
- @SafeVarargs
- public static <T> void assertUnorderedCollection(@NotNull T[] collection, @NotNull Consumer<T>... checkers) {
- assertUnorderedCollection(Arrays.asList(collection), checkers);
- }
-
- @SafeVarargs
- public static <T> void assertUnorderedCollection(@NotNull Collection<? extends T> collection, @NotNull Consumer<T>... checkers) {
- if (collection.size() != checkers.length) {
- Assert.fail(toString(collection));
- }
- Set<Consumer<T>> checkerSet = new HashSet<>(Arrays.asList(checkers));
- int i = 0;
- Throwable lastError = null;
- for (final T actual : collection) {
- boolean flag = true;
- for (final Consumer<T> condition : checkerSet) {
- Throwable error = accepts(condition, actual);
- if (error == null) {
- checkerSet.remove(condition);
- flag = false;
- break;
- }
- else {
- lastError = error;
- }
- }
- if (flag) {
- //noinspection ConstantConditions,CallToPrintStackTrace
- lastError.printStackTrace();
- Assert.fail("Incorrect element(" + i + "): " + actual);
- }
- i++;
- }
- }
-
- private static <T> Throwable accepts(@NotNull Consumer<? super T> condition, final T actual) {
- try {
- condition.consume(actual);
- return null;
- }
- catch (Throwable e) {
- return e;
- }
- }
-
- @Contract("null, _ -> fail")
- @NotNull
- public static <T> T assertInstanceOf(Object o, @NotNull Class<T> aClass) {
- Assert.assertNotNull("Expected instance of: " + aClass.getName() + " actual: " + null, o);
- Assert.assertTrue("Expected instance of: " + aClass.getName() + " actual: " + o.getClass().getName(), aClass.isInstance(o));
- @SuppressWarnings("unchecked") T t = (T)o;
- return t;
- }
-
- public static <T> T assertOneElement(@NotNull Collection<? extends T> collection) {
- Iterator<? extends T> iterator = collection.iterator();
- String toString = toString(collection);
- Assert.assertTrue(toString, iterator.hasNext());
- T t = iterator.next();
- Assert.assertFalse(toString, iterator.hasNext());
- return t;
- }
-
- public static <T> T assertOneElement(@NotNull T[] ts) {
- Assert.assertEquals(Arrays.asList(ts).toString(), 1, ts.length);
- return ts[0];
- }
-
- @SafeVarargs
- public static <T> void assertOneOf(T value, @NotNull T... values) {
- for (T v : values) {
- if (Objects.equals(value, v)) {
- return;
- }
- }
- Assert.fail(value + " should be equal to one of " + Arrays.toString(values));
- }
-
- public static void printThreadDump() {
- PerformanceWatcher.dumpThreadsToConsole("Thread dump:");
- }
-
- public static void assertEmpty(@NotNull Object[] array) {
- assertOrderedEquals(array);
- }
-
- public static void assertNotEmpty(final Collection<?> collection) {
- assertNotNull(collection);
- assertFalse(collection.isEmpty());
- }
-
- public static void assertEmpty(@NotNull Collection<?> collection) {
- assertEmpty(collection.toString(), collection);
- }
-
- public static void assertNullOrEmpty(@Nullable Collection<?> collection) {
- if (collection == null) return;
- assertEmpty("", collection);
- }
-
- public static void assertEmpty(final String s) {
- assertTrue(s, StringUtil.isEmpty(s));
- }
-
- public static <T> void assertEmpty(@NotNull String errorMsg, @NotNull Collection<? extends T> collection) {
- assertOrderedEquals(errorMsg, collection, Collections.emptyList());
- }
-
- public static void assertSize(int expectedSize, @NotNull Object[] array) {
- if (array.length != expectedSize) {
- assertEquals(toString(Arrays.asList(array)), expectedSize, array.length);
- }
- }
-
- public static void assertSize(int expectedSize, @NotNull Collection<?> c) {
- if (c.size() != expectedSize) {
- assertEquals(toString(c), expectedSize, c.size());
- }
- }
-
- @NotNull
- protected <T extends Disposable> T disposeOnTearDown(@NotNull T disposable) {
- Disposer.register(getTestRootDisposable(), disposable);
- return disposable;
- }
-
- public static void assertSameLines(@NotNull String expected, @NotNull String actual) {
- assertSameLines(null, expected, actual);
- }
-
- public static void assertSameLines(@Nullable String message, @NotNull String expected, @NotNull String actual) {
- String expectedText = StringUtil.convertLineSeparators(expected.trim());
- String actualText = StringUtil.convertLineSeparators(actual.trim());
- Assert.assertEquals(message, expectedText, actualText);
- }
-
- public static void assertExists(@NotNull File file){
- assertTrue("File should exist " + file, file.exists());
- }
-
- public static void assertDoesntExist(@NotNull File file){
- assertFalse("File should not exist " + file, file.exists());
- }
-
- @NotNull
- protected String getTestName(boolean lowercaseFirstLetter) {
- return getTestName(getName(), lowercaseFirstLetter);
- }
-
- @NotNull
- public static String getTestName(@Nullable String name, boolean lowercaseFirstLetter) {
- return name == null ? "" : PlatformTestUtil.getTestName(name, lowercaseFirstLetter);
- }
-
- @NotNull
- protected String getTestDirectoryName() {
- final String testName = getTestName(true);
- return testName.replaceAll("_.*", "");
- }
-
- public static void assertSameLinesWithFile(@NotNull String filePath, @NotNull String actualText) {
- assertSameLinesWithFile(filePath, actualText, true);
- }
-
- public static void assertSameLinesWithFile(@NotNull String filePath,
- @NotNull String actualText,
- @NotNull Supplier<String> messageProducer) {
- assertSameLinesWithFile(filePath, actualText, true, messageProducer);
- }
-
- public static void assertSameLinesWithFile(@NotNull String filePath, @NotNull String actualText, boolean trimBeforeComparing) {
- assertSameLinesWithFile(filePath, actualText, trimBeforeComparing, null);
- }
-
- public static void assertSameLinesWithFile(@NotNull String filePath,
- @NotNull String actualText,
- boolean trimBeforeComparing,
- @Nullable Supplier<String> messageProducer) {
- String fileText;
- try {
- if (OVERWRITE_TESTDATA) {
- VfsTestUtil.overwriteTestData(filePath, actualText);
- //noinspection UseOfSystemOutOrSystemErr
- System.out.println("File " + filePath + " created.");
- }
- fileText = FileUtil.loadFile(new File(filePath), CharsetToolkit.UTF8_CHARSET);
- }
- catch (FileNotFoundException e) {
- VfsTestUtil.overwriteTestData(filePath, actualText);
- throw new AssertionFailedError("No output text found. File " + filePath + " created.");
- }
- catch (IOException e) {
- throw new RuntimeException(e);
- }
- String expected = StringUtil.convertLineSeparators(trimBeforeComparing ? fileText.trim() : fileText);
- String actual = StringUtil.convertLineSeparators(trimBeforeComparing ? actualText.trim() : actualText);
- if (!Comparing.equal(expected, actual)) {
- throw new FileComparisonFailure(messageProducer == null ? null : messageProducer.get(), expected, actual, filePath);
- }
- }
-
- protected static void clearFields(@NotNull Object test) throws IllegalAccessException {
- Class aClass = test.getClass();
- while (aClass != null) {
- clearDeclaredFields(test, aClass);
- aClass = aClass.getSuperclass();
- }
- }
-
- public static void clearDeclaredFields(@NotNull Object test, @NotNull Class aClass) throws IllegalAccessException {
- for (final Field field : aClass.getDeclaredFields()) {
- final String name = field.getDeclaringClass().getName();
- if (!name.startsWith("junit.framework.") && !name.startsWith("com.intellij.testFramework.")) {
- final int modifiers = field.getModifiers();
- if ((modifiers & Modifier.FINAL) == 0 && (modifiers & Modifier.STATIC) == 0 && !field.getType().isPrimitive()) {
- field.setAccessible(true);
- field.set(test, null);
- }
- }
- }
- }
-
- private static void checkCodeStyleSettingsEqual(@NotNull CodeStyleSettings expected, @NotNull CodeStyleSettings settings) {
- if (!expected.equals(settings)) {
- Element oldS = new Element("temp");
- expected.writeExternal(oldS);
- Element newS = new Element("temp");
- settings.writeExternal(newS);
-
- String newString = JDOMUtil.writeElement(newS);
- String oldString = JDOMUtil.writeElement(oldS);
- Assert.assertEquals("Code style settings damaged", oldString, newString);
- }
- }
-
- public boolean isPerformanceTest() {
- String testName = getName();
- String className = getClass().getSimpleName();
- return TestFrameworkUtil.isPerformanceTest(testName, className);
- }
-
- /**
- * @return true for a test which performs A LOT of computations.
- * Such test should typically avoid performing expensive checks, e.g. data structure consistency complex validations.
- * If you want your test to be treated as "Stress", please mention one of these words in its name: "Stress", "Slow".
- * For example: {@code public void testStressPSIFromDifferentThreads()}
- */
- public boolean isStressTest() {
- return isStressTest(getName(), getClass().getName());
- }
-
- private static boolean isStressTest(String testName, String className) {
- return TestFrameworkUtil.isPerformanceTest(testName, className) ||
- containsStressWords(testName) ||
- containsStressWords(className);
- }
-
- private static boolean containsStressWords(@Nullable String name) {
- return name != null && (name.contains("Stress") || name.contains("Slow"));
- }
-
-
- /**
- * Checks that code block throw corresponding exception with expected error msg.
- * If expected error message is null it will not be checked.
- *
- * @param exceptionCase Block annotated with some exception type
- * @param expectedErrorMsg expected error message
- */
- protected void assertException(@NotNull AbstractExceptionCase exceptionCase, @Nullable String expectedErrorMsg) {
- //noinspection unchecked
- assertExceptionOccurred(true, exceptionCase, expectedErrorMsg);
- }
-
- /**
- * Checks that code block doesn't throw corresponding exception.
- *
- * @param exceptionCase Block annotated with some exception type
- */
- protected <T extends Throwable> void assertNoException(@NotNull AbstractExceptionCase<T> exceptionCase) throws T {
- assertExceptionOccurred(false, exceptionCase, null);
- }
-
- protected void assertNoThrowable(@NotNull Runnable closure) {
- String throwableName = null;
- try {
- closure.run();
- }
- catch (Throwable thr) {
- throwableName = thr.getClass().getName();
- }
- assertNull(throwableName);
- }
-
- private static <T extends Throwable> void assertExceptionOccurred(boolean shouldOccur,
- @NotNull AbstractExceptionCase<T> exceptionCase,
- String expectedErrorMsg) throws T {
- boolean wasThrown = false;
- try {
- exceptionCase.tryClosure();
- }
- catch (Throwable e) {
- if (shouldOccur) {
- wasThrown = true;
- final String errorMessage = exceptionCase.getAssertionErrorMessage();
- assertEquals(errorMessage, exceptionCase.getExpectedExceptionClass(), e.getClass());
- if (expectedErrorMsg != null) {
- assertEquals("Compare error messages", expectedErrorMsg, e.getMessage());
- }
- }
- else if (exceptionCase.getExpectedExceptionClass().equals(e.getClass())) {
- wasThrown = true;
-
- //noinspection UseOfSystemOutOrSystemErr
- System.out.println();
- //noinspection UseOfSystemOutOrSystemErr
- e.printStackTrace(System.out);
-
- fail("Exception isn't expected here. Exception message: " + e.getMessage());
- }
- else {
- throw e;
- }
- }
- finally {
- if (shouldOccur && !wasThrown) {
- fail(exceptionCase.getAssertionErrorMessage());
- }
- }
- }
-
- protected boolean annotatedWith(@NotNull Class<? extends Annotation> annotationClass) {
- Class<?> aClass = getClass();
- String methodName = "test" + getTestName(false);
- boolean methodChecked = false;
- while (aClass != null && aClass != Object.class) {
- if (aClass.getAnnotation(annotationClass) != null) return true;
- if (!methodChecked) {
- Method method = ReflectionUtil.getDeclaredMethod(aClass, methodName);
- if (method != null) {
- if (method.getAnnotation(annotationClass) != null) return true;
- methodChecked = true;
- }
- }
- aClass = aClass.getSuperclass();
- }
- return false;
- }
-
- @NotNull
- protected String getHomePath() {
- return PathManager.getHomePath().replace(File.separatorChar, '/');
- }
-
- public static void refreshRecursively(@NotNull VirtualFile file) {
- VfsUtilCore.visitChildrenRecursively(file, new VirtualFileVisitor() {
- @Override
- public boolean visitFile(@NotNull VirtualFile file) {
- file.getChildren();
- return true;
- }
- });
- file.refresh(false, true);
- }
-
- @Nullable
- public static VirtualFile refreshAndFindFile(@NotNull final File file) {
- return UIUtil.invokeAndWaitIfNeeded(() -> LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file));
- }
-
- protected class TestDisposable implements Disposable {
- private volatile boolean myDisposed;
-
- public TestDisposable() {
- }
-
- @Override
- public void dispose() {
- myDisposed = true;
- }
-
- public boolean isDisposed() {
- return myDisposed;
- }
-
- @Override
- public String toString() {
- String testName = getTestName(false);
- return KtUsefulTestCase.this.getClass() + (StringUtil.isEmpty(testName) ? "" : ".test" + testName);
- }
- };
-}
+/*
+ * Copyright 2010-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 org.jetbrains.kotlin.test.testFramework;
+
+import com.intellij.codeInsight.CodeInsightSettings;
+import com.intellij.concurrency.IdeaForkJoinWorkerThreadFactory;
+import com.intellij.diagnostic.PerformanceWatcher;
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.application.Application;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.application.PathManager;
+import com.intellij.openapi.application.impl.ApplicationInfoImpl;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.fileTypes.StdFileTypes;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Comparing;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.openapi.util.IconLoader;
+import com.intellij.openapi.util.JDOMUtil;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.openapi.vfs.LocalFileSystem;
+import com.intellij.openapi.vfs.VfsUtilCore;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.openapi.vfs.VirtualFileVisitor;
+import com.intellij.psi.PsiDocumentManager;
+import com.intellij.psi.codeStyle.CodeStyleSettings;
+import com.intellij.psi.impl.DocumentCommitProcessor;
+import com.intellij.psi.impl.DocumentCommitThread;
+import com.intellij.psi.impl.source.PostprocessReformattingAspect;
+import com.intellij.rt.execution.junit.FileComparisonFailure;
+import com.intellij.testFramework.*;
+import com.intellij.testFramework.exceptionCases.AbstractExceptionCase;
+import com.intellij.testFramework.fixtures.IdeaTestExecutionPolicy;
+import com.intellij.util.*;
+import com.intellij.util.containers.ContainerUtil;
+import com.intellij.util.containers.PeekableIterator;
+import com.intellij.util.containers.PeekableIteratorWrapper;
+import com.intellij.util.indexing.FileBasedIndex;
+import com.intellij.util.indexing.FileBasedIndexImpl;
+import com.intellij.util.lang.CompoundRuntimeException;
+import com.intellij.util.ui.UIUtil;
+import gnu.trove.Equality;
+import gnu.trove.THashSet;
+import junit.framework.AssertionFailedError;
+import junit.framework.TestCase;
+import org.jdom.Element;
+import org.jetbrains.annotations.Contract;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.kotlin.testFramework.MockComponentManagerCreationTracer;
+import org.junit.Assert;
+import org.junit.ComparisonFailure;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Path;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Supplier;
+
+/**
+ * @author peter
+ */
+@SuppressWarnings("ALL")
+public abstract class KtUsefulTestCase extends TestCase {
+ public static final boolean IS_UNDER_TEAMCITY = System.getenv("TEAMCITY_VERSION") != null;
+ public static final String TEMP_DIR_MARKER = "unitTest_";
+ public static final boolean OVERWRITE_TESTDATA = Boolean.getBoolean("idea.tests.overwrite.data");
+
+ private static final String ORIGINAL_TEMP_DIR = FileUtil.getTempDirectory();
+
+ private static final Map<String, Long> TOTAL_SETUP_COST_MILLIS = new HashMap<>();
+ private static final Map<String, Long> TOTAL_TEARDOWN_COST_MILLIS = new HashMap<>();
+
+ private Application application;
+
+ static {
+ IdeaForkJoinWorkerThreadFactory.setupPoisonFactory();
+ Logger.setFactory(TestLoggerFactory.class);
+ }
+ protected static final Logger LOG = Logger.getInstance(KtUsefulTestCase.class);
+
+ @NotNull
+ private final Disposable myTestRootDisposable = new TestDisposable();
+
+ static Path ourPathToKeep;
+ private final List<String> myPathsToKeep = new ArrayList<>();
+
+ private String myTempDir;
+
+ private static final String DEFAULT_SETTINGS_EXTERNALIZED;
+ private static final CodeInsightSettings defaultSettings = new CodeInsightSettings();
+ static {
+ // Radar #5755208: Command line Java applications need a way to launch without a Dock icon.
+ System.setProperty("apple.awt.UIElement", "true");
+
+ try {
+ Element oldS = new Element("temp");
+ defaultSettings.writeExternal(oldS);
+ DEFAULT_SETTINGS_EXTERNALIZED = JDOMUtil.writeElement(oldS);
+ }
+ catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Pass here the exception you want to be thrown first
+ * E.g.<pre>
+ * {@code
+ * void tearDown() {
+ * try {
+ * doTearDowns();
+ * }
+ * catch(Exception e) {
+ * addSuppressedException(e);
+ * }
+ * finally {
+ * super.tearDown();
+ * }
+ * }
+ * }
+ * </pre>
+ *
+ */
+ protected void addSuppressedException(@NotNull Throwable e) {
+ List<Throwable> list = mySuppressedExceptions;
+ if (list == null) {
+ mySuppressedExceptions = list = new SmartList<>();
+ }
+ list.add(e);
+ }
+ private List<Throwable> mySuppressedExceptions;
+
+
+ public KtUsefulTestCase() {
+ }
+
+ public KtUsefulTestCase(@NotNull String name) {
+ super(name);
+ }
+
+ protected boolean shouldContainTempFiles() {
+ return true;
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ // -- KOTLIN ADDITIONAL START --
+ application = ApplicationManager.getApplication();
+
+ if (application != null && application.isDisposed()) {
+ MockComponentManagerCreationTracer.diagnoseDisposedButNotClearedApplication(application);
+ }
+ // -- KOTLIN ADDITIONAL END --
+
+ super.setUp();
+
+ if (shouldContainTempFiles()) {
+ IdeaTestExecutionPolicy policy = IdeaTestExecutionPolicy.current();
+ String testName = null;
+ if (policy != null) {
+ testName = policy.getPerTestTempDirName();
+ }
+ if (testName == null) {
+ testName = FileUtil.sanitizeFileName(getTestName(true));
+ }
+ testName = new File(testName).getName(); // in case the test name contains file separators
+ myTempDir = FileUtil.createTempDirectory(TEMP_DIR_MARKER + testName, "", false).getPath();
+ FileUtil.resetCanonicalTempPathCache(myTempDir);
+ }
+
+ boolean isStressTest = isStressTest();
+ ApplicationInfoImpl.setInStressTest(isStressTest);
+ if (isPerformanceTest()) {
+ Timings.getStatistics();
+ }
+
+ // turn off Disposer debugging for performance tests
+ Disposer.setDebugMode(!isStressTest);
+
+ if (isIconRequired()) {
+ // ensure that IconLoader will use dummy empty icon
+ IconLoader.deactivate();
+ //IconManager.activate();
+ }
+ }
+
+ protected boolean isIconRequired() {
+ return false;
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ try {
+ // don't use method references here to make stack trace reading easier
+ //noinspection Convert2MethodRef
+ new RunAll(
+ () -> {
+ if (isIconRequired()) {
+ //IconManager.deactivate();
+ }
+ },
+ () -> disposeRootDisposable(),
+ () -> cleanupSwingDataStructures(),
+ () -> cleanupDeleteOnExitHookList(),
+ () -> Disposer.setDebugMode(true),
+ () -> {
+ if (shouldContainTempFiles()) {
+ FileUtil.resetCanonicalTempPathCache(ORIGINAL_TEMP_DIR);
+ if (hasTmpFilesToKeep()) {
+ File[] files = new File(myTempDir).listFiles();
+ if (files != null) {
+ for (File file : files) {
+ if (!shouldKeepTmpFile(file)) {
+ FileUtil.delete(file);
+ }
+ }
+ }
+ }
+ else {
+ FileUtil.delete(new File(myTempDir));
+ }
+ }
+ },
+ () -> waitForAppLeakingThreads(10, TimeUnit.SECONDS)
+ ).run(ObjectUtils.notNull(mySuppressedExceptions, Collections.emptyList()));
+ }
+ finally {
+ // -- KOTLIN ADDITIONAL START --
+ TestApplicationUtilKt.resetApplicationToNull(application);
+ application = null;
+ // -- KOTLIN ADDITIONAL END --
+ }
+ }
+
+ protected final void disposeRootDisposable() {
+ Disposer.dispose(getTestRootDisposable());
+ }
+
+ protected void addTmpFileToKeep(@NotNull File file) {
+ myPathsToKeep.add(file.getPath());
+ }
+
+ private boolean hasTmpFilesToKeep() {
+ return ourPathToKeep != null && FileUtil.isAncestor(myTempDir, ourPathToKeep.toString(), false) || !myPathsToKeep.isEmpty();
+ }
+
+ private boolean shouldKeepTmpFile(@NotNull File file) {
+ String path = file.getPath();
+ if (FileUtil.pathsEqual(path, ourPathToKeep.toString())) return true;
+ for (String pathToKeep : myPathsToKeep) {
+ if (FileUtil.pathsEqual(path, pathToKeep)) return true;
+ }
+ return false;
+ }
+
+ private static final Set<String> DELETE_ON_EXIT_HOOK_DOT_FILES;
+ private static final Class<?> DELETE_ON_EXIT_HOOK_CLASS;
+ static {
+ Class<?> aClass;
+ try {
+ aClass = Class.forName("java.io.DeleteOnExitHook");
+ }
+ catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ @SuppressWarnings("unchecked") Set<String> files = ReflectionUtil.getStaticFieldValue(aClass, Set.class, "files");
+ DELETE_ON_EXIT_HOOK_CLASS = aClass;
+ DELETE_ON_EXIT_HOOK_DOT_FILES = files;
+ }
+
+ @SuppressWarnings("SynchronizeOnThis")
+ private static void cleanupDeleteOnExitHookList() {
+ // try to reduce file set retained by java.io.DeleteOnExitHook
+ List<String> list;
+ synchronized (DELETE_ON_EXIT_HOOK_CLASS) {
+ if (DELETE_ON_EXIT_HOOK_DOT_FILES.isEmpty()) return;
+ list = new ArrayList<>(DELETE_ON_EXIT_HOOK_DOT_FILES);
+ }
+ for (int i = list.size() - 1; i >= 0; i--) {
+ String path = list.get(i);
+ File file = new File(path);
+ if (file.delete() || !file.exists()) {
+ synchronized (DELETE_ON_EXIT_HOOK_CLASS) {
+ DELETE_ON_EXIT_HOOK_DOT_FILES.remove(path);
+ }
+ }
+ }
+ }
+
+ @SuppressWarnings("ConstantConditions")
+ private static void cleanupSwingDataStructures() throws Exception {
+ Object manager = ReflectionUtil.getDeclaredMethod(Class.forName("javax.swing.KeyboardManager"), "getCurrentManager").invoke(null);
+ Map<?, ?> componentKeyStrokeMap = ReflectionUtil.getField(manager.getClass(), manager, Hashtable.class, "componentKeyStrokeMap");
+ componentKeyStrokeMap.clear();
+ Map<?, ?> containerMap = ReflectionUtil.getField(manager.getClass(), manager, Hashtable.class, "containerMap");
+ containerMap.clear();
+ }
+
+ static void doCheckForSettingsDamage(@NotNull CodeStyleSettings oldCodeStyleSettings, @NotNull CodeStyleSettings currentCodeStyleSettings) {
+ final CodeInsightSettings settings = CodeInsightSettings.getInstance();
+ // don't use method references here to make stack trace reading easier
+ //noinspection Convert2MethodRef
+ new RunAll()
+ .append(() -> {
+ try {
+ checkCodeInsightSettingsEqual(defaultSettings, settings);
+ }
+ catch (AssertionError error) {
+ CodeInsightSettings clean = new CodeInsightSettings();
+ for (Field field : clean.getClass().getFields()) {
+ try {
+ ReflectionUtil.copyFieldValue(clean, settings, field);
+ }
+ catch (Exception ignored) {
+ }
+ }
+ throw error;
+ }
+ })
+ .append(() -> {
+ currentCodeStyleSettings.getIndentOptions(StdFileTypes.JAVA);
+ try {
+ checkCodeStyleSettingsEqual(oldCodeStyleSettings, currentCodeStyleSettings);
+ }
+ finally {
+ currentCodeStyleSettings.clearCodeStyleSettings();
+ }
+ })
+ .run();
+ }
+
+ @NotNull
+ public Disposable getTestRootDisposable() {
+ return myTestRootDisposable;
+ }
+
+ @Override
+ protected void runTest() throws Throwable {
+ final Throwable[] throwables = new Throwable[1];
+
+ Runnable runnable = () -> {
+ try {
+ TestLoggerFactory.onTestStarted();
+ super.runTest();
+ TestLoggerFactory.onTestFinished(true);
+ }
+ catch (InvocationTargetException e) {
+ TestLoggerFactory.onTestFinished(false);
+ e.fillInStackTrace();
+ throwables[0] = e.getTargetException();
+ }
+ catch (IllegalAccessException e) {
+ TestLoggerFactory.onTestFinished(false);
+ e.fillInStackTrace();
+ throwables[0] = e;
+ }
+ catch (Throwable e) {
+ TestLoggerFactory.onTestFinished(false);
+ throwables[0] = e;
+ }
+ };
+
+ invokeTestRunnable(runnable);
+
+ if (throwables[0] != null) {
+ throw throwables[0];
+ }
+ }
+
+ protected boolean shouldRunTest() {
+ return TestFrameworkUtil.canRunTest(getClass());
+ }
+
+ protected void invokeTestRunnable(@NotNull Runnable runnable) throws Exception {
+ if (runInDispatchThread()) {
+ EdtTestUtilKt.runInEdtAndWait(() -> {
+ runnable.run();
+ return null;
+ });
+ }
+ else {
+ runnable.run();
+ }
+ }
+
+ protected void defaultRunBare() throws Throwable {
+ Throwable exception = null;
+ try {
+ long setupStart = System.nanoTime();
+ setUp();
+ long setupCost = (System.nanoTime() - setupStart) / 1000000;
+ logPerClassCost(setupCost, TOTAL_SETUP_COST_MILLIS);
+
+ runTest();
+ }
+ catch (Throwable running) {
+ exception = running;
+ }
+ finally {
+ try {
+ long teardownStart = System.nanoTime();
+ tearDown();
+ long teardownCost = (System.nanoTime() - teardownStart) / 1000000;
+ logPerClassCost(teardownCost, TOTAL_TEARDOWN_COST_MILLIS);
+ }
+ catch (Throwable tearingDown) {
+ if (exception == null) {
+ exception = tearingDown;
+ }
+ else {
+ exception = new CompoundRuntimeException(Arrays.asList(exception, tearingDown));
+ }
+ }
+ }
+ if (exception != null) {
+ throw exception;
+ }
+ }
+
+ /**
+ * Logs the setup cost grouped by test fixture class (superclass of the current test class).
+ *
+ * @param cost setup cost in milliseconds
+ */
+ private void logPerClassCost(long cost, @NotNull Map<String, Long> costMap) {
+ Class<?> superclass = getClass().getSuperclass();
+ Long oldCost = costMap.get(superclass.getName());
+ long newCost = oldCost == null ? cost : oldCost + cost;
+ costMap.put(superclass.getName(), newCost);
+ }
+
+ @SuppressWarnings("UseOfSystemOutOrSystemErr")
+ static void logSetupTeardownCosts() {
+ System.out.println("Setup costs");
+ long totalSetup = 0;
+ for (Map.Entry<String, Long> entry : TOTAL_SETUP_COST_MILLIS.entrySet()) {
+ System.out.println(String.format(" %s: %d ms", entry.getKey(), entry.getValue()));
+ totalSetup += entry.getValue();
+ }
+ System.out.println("Teardown costs");
+ long totalTeardown = 0;
+ for (Map.Entry<String, Long> entry : TOTAL_TEARDOWN_COST_MILLIS.entrySet()) {
+ System.out.println(String.format(" %s: %d ms", entry.getKey(), entry.getValue()));
+ totalTeardown += entry.getValue();
+ }
+ System.out.println(String.format("Total overhead: setup %d ms, teardown %d ms", totalSetup, totalTeardown));
+ System.out.println(String.format("##teamcity[buildStatisticValue key='ideaTests.totalSetupMs' value='%d']", totalSetup));
+ System.out.println(String.format("##teamcity[buildStatisticValue key='ideaTests.totalTeardownMs' value='%d']", totalTeardown));
+ }
+
+ @Override
+ public void runBare() throws Throwable {
+ if (!shouldRunTest()) return;
+
+ if (runInDispatchThread()) {
+ TestRunnerUtil.replaceIdeEventQueueSafely();
+ EdtTestUtil.runInEdtAndWait(this::defaultRunBare);
+ }
+ else {
+ defaultRunBare();
+ }
+ }
+
+ protected boolean runInDispatchThread() {
+ IdeaTestExecutionPolicy policy = IdeaTestExecutionPolicy.current();
+ if (policy != null) {
+ return policy.runInDispatchThread();
+ }
+ return true;
+ }
+
+ /**
+ * If you want a more shorter name than runInEdtAndWait.
+ */
+ protected void edt(@NotNull ThrowableRunnable<Throwable> runnable) {
+ EdtTestUtil.runInEdtAndWait(runnable);
+ }
+
+ @NotNull
+ public static String toString(@NotNull Iterable<?> collection) {
+ if (!collection.iterator().hasNext()) {
+ return "<empty>";
+ }
+
+ final StringBuilder builder = new StringBuilder();
+ for (final Object o : collection) {
+ if (o instanceof THashSet) {
+ builder.append(new TreeSet<>((THashSet<?>)o));
+ }
+ else {
+ builder.append(o);
+ }
+ builder.append('\n');
+ }
+ return builder.toString();
+ }
+
+ @SafeVarargs
+ public static <T> void assertOrderedEquals(@NotNull T[] actual, @NotNull T... expected) {
+ assertOrderedEquals(Arrays.asList(actual), expected);
+ }
+
+ @SafeVarargs
+ public static <T> void assertOrderedEquals(@NotNull Iterable<? extends T> actual, @NotNull T... expected) {
+ assertOrderedEquals("", actual, expected);
+ }
+
+ public static void assertOrderedEquals(@NotNull byte[] actual, @NotNull byte[] expected) {
+ assertEquals(expected.length, actual.length);
+ for (int i = 0; i < actual.length; i++) {
+ byte a = actual[i];
+ byte e = expected[i];
+ assertEquals("not equals at index: "+i, e, a);
+ }
+ }
+
+ public static void assertOrderedEquals(@NotNull int[] actual, @NotNull int[] expected) {
+ if (actual.length != expected.length) {
+ fail("Expected size: "+expected.length+"; actual: "+actual.length+"\nexpected: "+Arrays.toString(expected)+"\nactual : "+Arrays.toString(actual));
+ }
+ for (int i = 0; i < actual.length; i++) {
+ int a = actual[i];
+ int e = expected[i];
+ assertEquals("not equals at index: "+i, e, a);
+ }
+ }
+
+ @SafeVarargs
+ public static <T> void assertOrderedEquals(@NotNull String errorMsg, @NotNull Iterable<? extends T> actual, @NotNull T... expected) {
+ assertOrderedEquals(errorMsg, actual, Arrays.asList(expected));
+ }
+
+ public static <T> void assertOrderedEquals(@NotNull Iterable<? extends T> actual, @NotNull Iterable<? extends T> expected) {
+ assertOrderedEquals("", actual, expected);
+ }
+
+ public static <T> void assertOrderedEquals(@NotNull String errorMsg,
+ @NotNull Iterable<? extends T> actual,
+ @NotNull Iterable<? extends T> expected) {
+ //noinspection unchecked
+ assertOrderedEquals(errorMsg, actual, expected, Equality.CANONICAL);
+ }
+
+ public static <T> void assertOrderedEquals(@NotNull String errorMsg,
+ @NotNull Iterable<? extends T> actual,
+ @NotNull Iterable<? extends T> expected,
+ @NotNull Equality<? super T> comparator) {
+ if (!equals(actual, expected, comparator)) {
+ String expectedString = toString(expected);
+ String actualString = toString(actual);
+ Assert.assertEquals(errorMsg, expectedString, actualString);
+ Assert.fail("Warning! 'toString' does not reflect the difference.\nExpected: " + expectedString + "\nActual: " + actualString);
+ }
+ }
+
+ private static <T> boolean equals(@NotNull Iterable<? extends T> a1,
+ @NotNull Iterable<? extends T> a2,
+ @NotNull Equality<? super T> comparator) {
+ Iterator<? extends T> it1 = a1.iterator();
+ Iterator<? extends T> it2 = a2.iterator();
+ while (it1.hasNext() || it2.hasNext()) {
+ if (!it1.hasNext() || !it2.hasNext()) return false;
+ if (!comparator.equals(it1.next(), it2.next())) return false;
+ }
+ return true;
+ }
+
+ @SafeVarargs
+ public static <T> void assertOrderedCollection(@NotNull T[] collection, @NotNull Consumer<T>... checkers) {
+ assertOrderedCollection(Arrays.asList(collection), checkers);
+ }
+
+ /**
+ * Checks {@code actual} contains same elements (in {@link #equals(Object)} meaning) as {@code expected} irrespective of their order
+ */
+ @SafeVarargs
+ public static <T> void assertSameElements(@NotNull T[] actual, @NotNull T... expected) {
+ assertSameElements(Arrays.asList(actual), expected);
+ }
+
+ /**
+ * Checks {@code actual} contains same elements (in {@link #equals(Object)} meaning) as {@code expected} irrespective of their order
+ */
+ @SafeVarargs
+ public static <T> void assertSameElements(@NotNull Collection<? extends T> actual, @NotNull T... expected) {
+ assertSameElements(actual, Arrays.asList(expected));
+ }
+
+ /**
+ * Checks {@code actual} contains same elements (in {@link #equals(Object)} meaning) as {@code expected} irrespective of their order
+ */
+ public static <T> void assertSameElements(@NotNull Collection<? extends T> actual, @NotNull Collection<? extends T> expected) {
+ assertSameElements("", actual, expected);
+ }
+
+ /**
+ * Checks {@code actual} contains same elements (in {@link #equals(Object)} meaning) as {@code expected} irrespective of their order
+ */
+ public static <T> void assertSameElements(@NotNull String message, @NotNull Collection<? extends T> actual, @NotNull Collection<? extends T> expected) {
+ if (actual.size() != expected.size() || !new HashSet<>(expected).equals(new HashSet<T>(actual))) {
+ Assert.assertEquals(message, new HashSet<>(expected), new HashSet<T>(actual));
+ }
+ }
+
+ @SafeVarargs
+ public static <T> void assertContainsOrdered(@NotNull Collection<? extends T> collection, @NotNull T... expected) {
+ assertContainsOrdered(collection, Arrays.asList(expected));
+ }
+
+ public static <T> void assertContainsOrdered(@NotNull Collection<? extends T> collection, @NotNull Collection<? extends T> expected) {
+ PeekableIterator<T> expectedIt = new PeekableIteratorWrapper<>(expected.iterator());
+ PeekableIterator<T> actualIt = new PeekableIteratorWrapper<>(collection.iterator());
+
+ while (actualIt.hasNext() && expectedIt.hasNext()) {
+ T expectedElem = expectedIt.peek();
+ T actualElem = actualIt.peek();
+ if (expectedElem.equals(actualElem)) {
+ expectedIt.next();
+ }
+ actualIt.next();
+ }
+ if (expectedIt.hasNext()) {
+ throw new ComparisonFailure("", toString(expected), toString(collection));
+ }
+ }
+
+ @SafeVarargs
+ public static <T> void assertContainsElements(@NotNull Collection<? extends T> collection, @NotNull T... expected) {
+ assertContainsElements(collection, Arrays.asList(expected));
+ }
+
+ public static <T> void assertContainsElements(@NotNull Collection<? extends T> collection, @NotNull Collection<? extends T> expected) {
+ ArrayList<T> copy = new ArrayList<>(collection);
+ copy.retainAll(expected);
+ assertSameElements(toString(collection), copy, expected);
+ }
+
+ @NotNull
+ public static String toString(@NotNull Object[] collection, @NotNull String separator) {
+ return toString(Arrays.asList(collection), separator);
+ }
+
+ @SafeVarargs
+ public static <T> void assertDoesntContain(@NotNull Collection<? extends T> collection, @NotNull T... notExpected) {
+ assertDoesntContain(collection, Arrays.asList(notExpected));
+ }
+
+ public static <T> void assertDoesntContain(@NotNull Collection<? extends T> collection, @NotNull Collection<? extends T> notExpected) {
+ ArrayList<T> expected = new ArrayList<>(collection);
+ expected.removeAll(notExpected);
+ assertSameElements(collection, expected);
+ }
+
+ @NotNull
+ public static String toString(@NotNull Collection<?> collection, @NotNull String separator) {
+ List<String> list = ContainerUtil.map2List(collection, String::valueOf);
+ Collections.sort(list);
+ StringBuilder builder = new StringBuilder();
+ boolean flag = false;
+ for (final String o : list) {
+ if (flag) {
+ builder.append(separator);
+ }
+ builder.append(o);
+ flag = true;
+ }
+ return builder.toString();
+ }
+
+ @SafeVarargs
+ public static <T> void assertOrderedCollection(@NotNull Collection<? extends T> collection, @NotNull Consumer<T>... checkers) {
+ if (collection.size() != checkers.length) {
+ Assert.fail(toString(collection));
+ }
+ int i = 0;
+ for (final T actual : collection) {
+ try {
+ checkers[i].consume(actual);
+ }
+ catch (AssertionFailedError e) {
+ //noinspection UseOfSystemOutOrSystemErr
+ System.out.println(i + ": " + actual);
+ throw e;
+ }
+ i++;
+ }
+ }
+
+ @SafeVarargs
+ public static <T> void assertUnorderedCollection(@NotNull T[] collection, @NotNull Consumer<T>... checkers) {
+ assertUnorderedCollection(Arrays.asList(collection), checkers);
+ }
+
+ @SafeVarargs
+ public static <T> void assertUnorderedCollection(@NotNull Collection<? extends T> collection, @NotNull Consumer<T>... checkers) {
+ if (collection.size() != checkers.length) {
+ Assert.fail(toString(collection));
+ }
+ Set<Consumer<T>> checkerSet = ContainerUtil.set(checkers);
+ int i = 0;
+ Throwable lastError = null;
+ for (final T actual : collection) {
+ boolean flag = true;
+ for (final Consumer<T> condition : checkerSet) {
+ Throwable error = accepts(condition, actual);
+ if (error == null) {
+ checkerSet.remove(condition);
+ flag = false;
+ break;
+ }
+ else {
+ lastError = error;
+ }
+ }
+ if (flag) {
+ //noinspection ConstantConditions,CallToPrintStackTrace
+ lastError.printStackTrace();
+ Assert.fail("Incorrect element(" + i + "): " + actual);
+ }
+ i++;
+ }
+ }
+
+ private static <T> Throwable accepts(@NotNull Consumer<? super T> condition, final T actual) {
+ try {
+ condition.consume(actual);
+ return null;
+ }
+ catch (Throwable e) {
+ return e;
+ }
+ }
+
+ @Contract("null, _ -> fail")
+ @NotNull
+ public static <T> T assertInstanceOf(Object o, @NotNull Class<T> aClass) {
+ Assert.assertNotNull("Expected instance of: " + aClass.getName() + " actual: " + null, o);
+ Assert.assertTrue("Expected instance of: " + aClass.getName() + " actual: " + o.getClass().getName(), aClass.isInstance(o));
+ @SuppressWarnings("unchecked") T t = (T)o;
+ return t;
+ }
+
+ public static <T> T assertOneElement(@NotNull Collection<? extends T> collection) {
+ Iterator<? extends T> iterator = collection.iterator();
+ String toString = toString(collection);
+ Assert.assertTrue(toString, iterator.hasNext());
+ T t = iterator.next();
+ Assert.assertFalse(toString, iterator.hasNext());
+ return t;
+ }
+
+ public static <T> T assertOneElement(@NotNull T[] ts) {
+ Assert.assertEquals(Arrays.asList(ts).toString(), 1, ts.length);
+ return ts[0];
+ }
+
+ @SafeVarargs
+ public static <T> void assertOneOf(T value, @NotNull T... values) {
+ for (T v : values) {
+ if (Objects.equals(value, v)) {
+ return;
+ }
+ }
+ Assert.fail(value + " should be equal to one of " + Arrays.toString(values));
+ }
+
+ public static void printThreadDump() {
+ PerformanceWatcher.dumpThreadsToConsole("Thread dump:");
+ }
+
+ public static void assertEmpty(@NotNull Object[] array) {
+ assertOrderedEquals(array);
+ }
+
+ public static void assertNotEmpty(final Collection<?> collection) {
+ assertNotNull(collection);
+ assertFalse(collection.isEmpty());
+ }
+
+ public static void assertEmpty(@NotNull Collection<?> collection) {
+ assertEmpty(collection.toString(), collection);
+ }
+
+ public static void assertNullOrEmpty(@Nullable Collection<?> collection) {
+ if (collection == null) return;
+ assertEmpty("", collection);
+ }
+
+ public static void assertEmpty(final String s) {
+ assertTrue(s, StringUtil.isEmpty(s));
+ }
+
+ public static <T> void assertEmpty(@NotNull String errorMsg, @NotNull Collection<? extends T> collection) {
+ assertOrderedEquals(errorMsg, collection, Collections.emptyList());
+ }
+
+ public static void assertSize(int expectedSize, @NotNull Object[] array) {
+ if (array.length != expectedSize) {
+ assertEquals(toString(Arrays.asList(array)), expectedSize, array.length);
+ }
+ }
+
+ public static void assertSize(int expectedSize, @NotNull Collection<?> c) {
+ if (c.size() != expectedSize) {
+ assertEquals(toString(c), expectedSize, c.size());
+ }
+ }
+
+ @NotNull
+ protected <T extends Disposable> T disposeOnTearDown(@NotNull T disposable) {
+ Disposer.register(getTestRootDisposable(), disposable);
+ return disposable;
+ }
+
+ public static void assertSameLines(@NotNull String expected, @NotNull String actual) {
+ assertSameLines(null, expected, actual);
+ }
+
+ public static void assertSameLines(@Nullable String message, @NotNull String expected, @NotNull String actual) {
+ String expectedText = StringUtil.convertLineSeparators(expected.trim());
+ String actualText = StringUtil.convertLineSeparators(actual.trim());
+ Assert.assertEquals(message, expectedText, actualText);
+ }
+
+ public static void assertExists(@NotNull File file){
+ assertTrue("File should exist " + file, file.exists());
+ }
+
+ public static void assertDoesntExist(@NotNull File file){
+ assertFalse("File should not exist " + file, file.exists());
+ }
+
+ @NotNull
+ protected String getTestName(boolean lowercaseFirstLetter) {
+ return getTestName(getName(), lowercaseFirstLetter);
+ }
+
+ @NotNull
+ public static String getTestName(@Nullable String name, boolean lowercaseFirstLetter) {
+ return name == null ? "" : PlatformTestUtil.getTestName(name, lowercaseFirstLetter);
+ }
+
+ @NotNull
+ protected String getTestDirectoryName() {
+ final String testName = getTestName(true);
+ return testName.replaceAll("_.*", "");
+ }
+
+ public static void assertSameLinesWithFile(@NotNull String filePath, @NotNull String actualText) {
+ assertSameLinesWithFile(filePath, actualText, true);
+ }
+
+ public static void assertSameLinesWithFile(@NotNull String filePath,
+ @NotNull String actualText,
+ @NotNull Supplier<String> messageProducer) {
+ assertSameLinesWithFile(filePath, actualText, true, messageProducer);
+ }
+
+ public static void assertSameLinesWithFile(@NotNull String filePath, @NotNull String actualText, boolean trimBeforeComparing) {
+ assertSameLinesWithFile(filePath, actualText, trimBeforeComparing, null);
+ }
+
+ public static void assertSameLinesWithFile(@NotNull String filePath,
+ @NotNull String actualText,
+ boolean trimBeforeComparing,
+ @Nullable Supplier<String> messageProducer) {
+ String fileText;
+ try {
+ if (OVERWRITE_TESTDATA) {
+ VfsTestUtil.overwriteTestData(filePath, actualText);
+ //noinspection UseOfSystemOutOrSystemErr
+ System.out.println("File " + filePath + " created.");
+ }
+ fileText = FileUtil.loadFile(new File(filePath), StandardCharsets.UTF_8);
+ }
+ catch (FileNotFoundException e) {
+ VfsTestUtil.overwriteTestData(filePath, actualText);
+ throw new AssertionFailedError("No output text found. File " + filePath + " created.");
+ }
+ catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ String expected = StringUtil.convertLineSeparators(trimBeforeComparing ? fileText.trim() : fileText);
+ String actual = StringUtil.convertLineSeparators(trimBeforeComparing ? actualText.trim() : actualText);
+ if (!Comparing.equal(expected, actual)) {
+ throw new FileComparisonFailure(messageProducer == null ? null : messageProducer.get(), expected, actual, filePath);
+ }
+ }
+
+ protected static void clearFields(@NotNull Object test) throws IllegalAccessException {
+ Class<?> aClass = test.getClass();
+ while (aClass != null) {
+ clearDeclaredFields(test, aClass);
+ aClass = aClass.getSuperclass();
+ }
+ }
+
+ public static void clearDeclaredFields(@NotNull Object test, @NotNull Class<?> aClass) throws IllegalAccessException {
+ for (final Field field : aClass.getDeclaredFields()) {
+ final String name = field.getDeclaringClass().getName();
+ if (!name.startsWith("junit.framework.") && !name.startsWith("com.intellij.testFramework.")) {
+ final int modifiers = field.getModifiers();
+ if ((modifiers & Modifier.FINAL) == 0 && (modifiers & Modifier.STATIC) == 0 && !field.getType().isPrimitive()) {
+ field.setAccessible(true);
+ field.set(test, null);
+ }
+ }
+ }
+ }
+
+ private static void checkCodeStyleSettingsEqual(@NotNull CodeStyleSettings expected, @NotNull CodeStyleSettings settings) {
+ if (!expected.equals(settings)) {
+ Element oldS = new Element("temp");
+ expected.writeExternal(oldS);
+ Element newS = new Element("temp");
+ settings.writeExternal(newS);
+
+ String newString = JDOMUtil.writeElement(newS);
+ String oldString = JDOMUtil.writeElement(oldS);
+ Assert.assertEquals("Code style settings damaged", oldString, newString);
+ }
+ }
+
+ private static void checkCodeInsightSettingsEqual(@NotNull CodeInsightSettings oldSettings, @NotNull CodeInsightSettings settings) {
+ if (!oldSettings.equals(settings)) {
+ Element newS = new Element("temp");
+ settings.writeExternal(newS);
+ Assert.assertEquals("Code insight settings damaged", DEFAULT_SETTINGS_EXTERNALIZED, JDOMUtil.writeElement(newS));
+ }
+ }
+
+ public boolean isPerformanceTest() {
+ String testName = getName();
+ String className = getClass().getSimpleName();
+ return TestFrameworkUtil.isPerformanceTest(testName, className);
+ }
+
+ /**
+ * @return true for a test which performs A LOT of computations.
+ * Such test should typically avoid performing expensive checks, e.g. data structure consistency complex validations.
+ * If you want your test to be treated as "Stress", please mention one of these words in its name: "Stress", "Slow".
+ * For example: {@code public void testStressPSIFromDifferentThreads()}
+ */
+ public boolean isStressTest() {
+ return isStressTest(getName(), getClass().getName());
+ }
+
+ private static boolean isStressTest(String testName, String className) {
+ return TestFrameworkUtil.isPerformanceTest(testName, className) ||
+ containsStressWords(testName) ||
+ containsStressWords(className);
+ }
+
+ private static boolean containsStressWords(@Nullable String name) {
+ return name != null && (name.contains("Stress") || name.contains("Slow"));
+ }
+
+ public static void doPostponedFormatting(@NotNull Project project) {
+ DocumentUtil.writeInRunUndoTransparentAction(() -> {
+ PsiDocumentManager.getInstance(project).commitAllDocuments();
+ PostprocessReformattingAspect.getInstance(project).doPostponedFormatting();
+ });
+ }
+
+ /**
+ * Checks that code block throw corresponding exception.
+ *
+ * @param exceptionCase Block annotated with some exception type
+ */
+ protected void assertException(@NotNull AbstractExceptionCase<?> exceptionCase) {
+ assertException(exceptionCase, null);
+ }
+
+ /**
+ * Checks that code block throw corresponding exception with expected error msg.
+ * If expected error message is null it will not be checked.
+ *
+ * @param exceptionCase Block annotated with some exception type
+ * @param expectedErrorMsg expected error message
+ */
+ protected void assertException(@NotNull AbstractExceptionCase exceptionCase, @Nullable String expectedErrorMsg) {
+ //noinspection unchecked
+ assertExceptionOccurred(true, exceptionCase, expectedErrorMsg);
+ }
+
+ /**
+ * Checks that the code block throws an exception of the specified class.
+ *
+ * @param exceptionClass Expected exception type
+ * @param runnable Block annotated with some exception type
+ */
+ public static <T extends Throwable> void assertThrows(@NotNull Class<? extends Throwable> exceptionClass,
+ @NotNull ThrowableRunnable<T> runnable) {
+ assertThrows(exceptionClass, null, runnable);
+ }
+
+ /**
+ * Checks that the code block throws an exception of the specified class with expected error msg.
+ * If expected error message is null it will not be checked.
+ *
+ * @param exceptionClass Expected exception type
+ * @param expectedErrorMsgPart expected error message, of any
+ * @param runnable Block annotated with some exception type
+ */
+ @SuppressWarnings({"unchecked", "SameParameterValue"})
+ public static <T extends Throwable> void assertThrows(@NotNull Class<? extends Throwable> exceptionClass,
+ @Nullable String expectedErrorMsgPart,
+ @NotNull ThrowableRunnable<T> runnable) {
+ assertExceptionOccurred(true, new AbstractExceptionCase() {
+ @Override
+ public Class<Throwable> getExpectedExceptionClass() {
+ return (Class<Throwable>)exceptionClass;
+ }
+
+ @Override
+ public void tryClosure() throws Throwable {
+ runnable.run();
+ }
+ }, expectedErrorMsgPart);
+ }
+
+ /**
+ * Checks that code block doesn't throw corresponding exception.
+ *
+ * @param exceptionCase Block annotated with some exception type
+ */
+ protected <T extends Throwable> void assertNoException(@NotNull AbstractExceptionCase<T> exceptionCase) throws T {
+ assertExceptionOccurred(false, exceptionCase, null);
+ }
+
+ protected void assertNoThrowable(@NotNull Runnable closure) {
+ String throwableName = null;
+ try {
+ closure.run();
+ }
+ catch (Throwable thr) {
+ throwableName = thr.getClass().getName();
+ }
+ assertNull(throwableName);
+ }
+
+ private static <T extends Throwable> void assertExceptionOccurred(boolean shouldOccur,
+ @NotNull AbstractExceptionCase<T> exceptionCase,
+ String expectedErrorMsgPart) throws T {
+ boolean wasThrown = false;
+ try {
+ exceptionCase.tryClosure();
+ }
+ catch (Throwable e) {
+ Throwable cause = e;
+
+ if (shouldOccur) {
+ wasThrown = true;
+ final String errorMessage = exceptionCase.getAssertionErrorMessage();
+ assertEquals(errorMessage, exceptionCase.getExpectedExceptionClass(), cause.getClass());
+ if (expectedErrorMsgPart != null) {
+ assertTrue(cause.getMessage(), cause.getMessage().contains(expectedErrorMsgPart));
+ }
+ }
+ else if (exceptionCase.getExpectedExceptionClass().equals(cause.getClass())) {
+ wasThrown = true;
+
+ //noinspection UseOfSystemOutOrSystemErr
+ System.out.println();
+ //noinspection UseOfSystemOutOrSystemErr
+ e.printStackTrace(System.out);
+
+ fail("Exception isn't expected here. Exception message: " + cause.getMessage());
+ }
+ else {
+ throw e;
+ }
+ }
+ finally {
+ if (shouldOccur && !wasThrown) {
+ fail(exceptionCase.getAssertionErrorMessage());
+ }
+ }
+ }
+
+ protected boolean annotatedWith(@NotNull Class<? extends Annotation> annotationClass) {
+ Class<?> aClass = getClass();
+ String methodName = "test" + getTestName(false);
+ boolean methodChecked = false;
+ while (aClass != null && aClass != Object.class) {
+ if (aClass.getAnnotation(annotationClass) != null) return true;
+ if (!methodChecked) {
+ Method method = ReflectionUtil.getDeclaredMethod(aClass, methodName);
+ if (method != null) {
+ if (method.getAnnotation(annotationClass) != null) return true;
+ methodChecked = true;
+ }
+ }
+ aClass = aClass.getSuperclass();
+ }
+ return false;
+ }
+
+ @NotNull
+ protected String getHomePath() {
+ return PathManager.getHomePath().replace(File.separatorChar, '/');
+ }
+
+ public static void refreshRecursively(@NotNull VirtualFile file) {
+ VfsUtilCore.visitChildrenRecursively(file, new VirtualFileVisitor<Void>() {
+ @Override
+ public boolean visitFile(@NotNull VirtualFile file) {
+ file.getChildren();
+ return true;
+ }
+ });
+ file.refresh(false, true);
+ }
+
+ public static VirtualFile refreshAndFindFile(@NotNull final File file) {
+ return UIUtil.invokeAndWaitIfNeeded(() -> LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file));
+ }
+
+ public static void waitForAppLeakingThreads(long timeout, @NotNull TimeUnit timeUnit) {
+ EdtTestUtil.runInEdtAndWait(() -> {
+ Application app = ApplicationManager.getApplication();
+ if (app != null && !app.isDisposed()) {
+ FileBasedIndexImpl index = (FileBasedIndexImpl)app.getServiceIfCreated(FileBasedIndex.class);
+ if (index != null) {
+ index.getChangedFilesCollector().waitForVfsEventsExecuted(timeout, timeUnit);
+ }
+
+ DocumentCommitThread commitThread = (DocumentCommitThread)app.getServiceIfCreated(DocumentCommitProcessor.class);
+ if (commitThread != null) {
+ commitThread.waitForAllCommits(timeout, timeUnit);
+ }
+ }
+ });
+ }
+
+ protected class TestDisposable implements Disposable {
+ private volatile boolean myDisposed;
+
+ public TestDisposable() {
+ }
+
+ @Override
+ public void dispose() {
+ myDisposed = true;
+ }
+
+ public boolean isDisposed() {
+ return myDisposed;
+ }
+
+ @Override
+ public String toString() {
+ String testName = getTestName(false);
+ return KtUsefulTestCase.this.getClass() + (StringUtil.isEmpty(testName) ? "" : ".test" + testName);
+ }
+ }
+}
\ No newline at end of file
diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/test/testFramework/KtUsefulTestCase.java.193 b/compiler/tests-common/tests/org/jetbrains/kotlin/test/testFramework/KtUsefulTestCase.java.193
new file mode 100644
index 0000000..ccc59d2
--- /dev/null
+++ b/compiler/tests-common/tests/org/jetbrains/kotlin/test/testFramework/KtUsefulTestCase.java.193
@@ -0,0 +1,972 @@
+/*
+ * Copyright 2010-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 org.jetbrains.kotlin.test.testFramework;
+
+import com.intellij.diagnostic.PerformanceWatcher;
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.application.Application;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.application.PathManager;
+import com.intellij.openapi.application.impl.ApplicationInfoImpl;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.util.Comparing;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.openapi.util.JDOMUtil;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.openapi.vfs.*;
+import com.intellij.psi.codeStyle.CodeStyleSettings;
+import com.intellij.rt.execution.junit.FileComparisonFailure;
+import com.intellij.testFramework.*;
+import com.intellij.testFramework.exceptionCases.AbstractExceptionCase;
+import com.intellij.util.Consumer;
+import com.intellij.util.ReflectionUtil;
+import com.intellij.util.containers.ContainerUtil;
+import com.intellij.util.containers.hash.HashMap;
+import com.intellij.util.lang.CompoundRuntimeException;
+import com.intellij.util.ui.UIUtil;
+import gnu.trove.Equality;
+import gnu.trove.THashSet;
+import junit.framework.AssertionFailedError;
+import junit.framework.TestCase;
+import org.jdom.Element;
+import org.jetbrains.annotations.Contract;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.kotlin.test.IdeaSystemPropertiesForParallelRunConfigurator;
+import org.jetbrains.kotlin.testFramework.MockComponentManagerCreationTracer;
+import org.jetbrains.kotlin.types.AbstractTypeChecker;
+import org.jetbrains.kotlin.types.FlexibleTypeImpl;
+import org.junit.Assert;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.*;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Supplier;
+
+@SuppressWarnings("UseOfSystemOutOrSystemErr")
+public abstract class KtUsefulTestCase extends TestCase {
+ public static final boolean IS_UNDER_TEAMCITY = System.getenv("TEAMCITY_VERSION") != null;
+ private static final String TEMP_DIR_MARKER = "unitTest_";
+ public static final boolean OVERWRITE_TESTDATA = Boolean.getBoolean("idea.tests.overwrite.data");
+
+ private static final String ORIGINAL_TEMP_DIR = FileUtil.getTempDirectory();
+
+ private static final Map<String, Long> TOTAL_SETUP_COST_MILLIS = new HashMap<>();
+ private static final Map<String, Long> TOTAL_TEARDOWN_COST_MILLIS = new HashMap<>();
+
+ private Application application;
+
+ static {
+ IdeaSystemPropertiesForParallelRunConfigurator.setProperties();
+ //TODO: investigate and enable
+ //IdeaForkJoinWorkerThreadFactory.setupPoisonFactory();
+ Logger.setFactory(TestLoggerFactory.class);
+ }
+
+ @NotNull
+ protected final Disposable myTestRootDisposable = new TestDisposable();
+
+ private static final String ourPathToKeep = null;
+ private final List<String> myPathsToKeep = new ArrayList<>();
+
+ private File myTempDir;
+
+ static {
+ // Radar #5755208: Command line Java applications need a way to launch without a Dock icon.
+ System.setProperty("apple.awt.UIElement", "true");
+
+ FlexibleTypeImpl.RUN_SLOW_ASSERTIONS = true;
+ AbstractTypeChecker.RUN_SLOW_ASSERTIONS = true;
+ }
+
+ protected boolean shouldContainTempFiles() {
+ return true;
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ // -- KOTLIN ADDITIONAL START --
+ application = ApplicationManager.getApplication();
+
+ if (application != null && application.isDisposed()) {
+ MockComponentManagerCreationTracer.diagnoseDisposedButNotClearedApplication(application);
+ }
+ // -- KOTLIN ADDITIONAL END --
+
+ super.setUp();
+
+ if (shouldContainTempFiles()) {
+ String testName = FileUtil.sanitizeFileName(getTestName(true));
+ if (StringUtil.isEmptyOrSpaces(testName)) testName = "";
+ testName = new File(testName).getName(); // in case the test name contains file separators
+ myTempDir = FileUtil.createTempDirectory(TEMP_DIR_MARKER, testName, false);
+ FileUtil.resetCanonicalTempPathCache(myTempDir.getPath());
+ }
+
+ boolean isStressTest = isStressTest();
+ ApplicationInfoImpl.setInStressTest(isStressTest);
+ if (isPerformanceTest()) {
+ Timings.getStatistics();
+ }
+
+ // turn off Disposer debugging for performance tests
+ Disposer.setDebugMode(!isStressTest);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ try {
+ // don't use method references here to make stack trace reading easier
+ //noinspection Convert2MethodRef
+ new RunAll(
+ () -> disposeRootDisposable(),
+ () -> cleanupSwingDataStructures(),
+ () -> cleanupDeleteOnExitHookList(),
+ () -> Disposer.setDebugMode(true),
+ () -> {
+ if (shouldContainTempFiles()) {
+ FileUtil.resetCanonicalTempPathCache(ORIGINAL_TEMP_DIR);
+ if (hasTmpFilesToKeep()) {
+ File[] files = myTempDir.listFiles();
+ if (files != null) {
+ for (File file : files) {
+ if (!shouldKeepTmpFile(file)) {
+ FileUtil.delete(file);
+ }
+ }
+ }
+ }
+ else {
+ FileUtil.delete(myTempDir);
+ }
+ }
+ },
+ () -> UIUtil.removeLeakingAppleListeners()
+ ).run();
+ }
+ finally {
+ super.tearDown();
+ // -- KOTLIN ADDITIONAL START --
+ TestApplicationUtilKt.resetApplicationToNull(application);
+ application = null;
+ // -- KOTLIN ADDITIONAL END --
+ }
+ }
+
+ protected final void disposeRootDisposable() {
+ Disposer.dispose(getTestRootDisposable());
+ }
+
+ protected void addTmpFileToKeep(@NotNull File file) {
+ myPathsToKeep.add(file.getPath());
+ }
+
+ private boolean hasTmpFilesToKeep() {
+ return ourPathToKeep != null && FileUtil.isAncestor(myTempDir.getPath(), ourPathToKeep, false) || !myPathsToKeep.isEmpty();
+ }
+
+ private boolean shouldKeepTmpFile(@NotNull File file) {
+ String path = file.getPath();
+ if (FileUtil.pathsEqual(path, ourPathToKeep)) return true;
+ for (String pathToKeep : myPathsToKeep) {
+ if (FileUtil.pathsEqual(path, pathToKeep)) return true;
+ }
+ return false;
+ }
+
+ private static final Set<String> DELETE_ON_EXIT_HOOK_DOT_FILES;
+ private static final Class DELETE_ON_EXIT_HOOK_CLASS;
+ static {
+ Class<?> aClass;
+ try {
+ aClass = Class.forName("java.io.DeleteOnExitHook");
+ }
+ catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ @SuppressWarnings("unchecked") Set<String> files = ReflectionUtil.getStaticFieldValue(aClass, Set.class, "files");
+ DELETE_ON_EXIT_HOOK_CLASS = aClass;
+ DELETE_ON_EXIT_HOOK_DOT_FILES = files;
+ }
+
+ @SuppressWarnings("SynchronizeOnThis")
+ private static void cleanupDeleteOnExitHookList() {
+ // try to reduce file set retained by java.io.DeleteOnExitHook
+ List<String> list;
+ synchronized (DELETE_ON_EXIT_HOOK_CLASS) {
+ if (DELETE_ON_EXIT_HOOK_DOT_FILES.isEmpty()) return;
+ list = new ArrayList<>(DELETE_ON_EXIT_HOOK_DOT_FILES);
+ }
+ for (int i = list.size() - 1; i >= 0; i--) {
+ String path = list.get(i);
+ File file = new File(path);
+ if (file.delete() || !file.exists()) {
+ synchronized (DELETE_ON_EXIT_HOOK_CLASS) {
+ DELETE_ON_EXIT_HOOK_DOT_FILES.remove(path);
+ }
+ }
+ }
+ }
+
+ @SuppressWarnings("ConstantConditions")
+ private static void cleanupSwingDataStructures() throws Exception {
+ Object manager = ReflectionUtil.getDeclaredMethod(Class.forName("javax.swing.KeyboardManager"), "getCurrentManager").invoke(null);
+ Map componentKeyStrokeMap = ReflectionUtil.getField(manager.getClass(), manager, Hashtable.class, "componentKeyStrokeMap");
+ componentKeyStrokeMap.clear();
+ Map containerMap = ReflectionUtil.getField(manager.getClass(), manager, Hashtable.class, "containerMap");
+ containerMap.clear();
+ }
+
+ @NotNull
+ public Disposable getTestRootDisposable() {
+ return myTestRootDisposable;
+ }
+
+ @Override
+ protected void runTest() throws Throwable {
+ final Throwable[] throwables = new Throwable[1];
+
+ AtomicBoolean completed = new AtomicBoolean(false);
+ Runnable runnable = () -> {
+ try {
+ //TestLoggerFactory.onTestStarted();
+ super.runTest();
+ TestLoggerFactory.onTestFinished(true);
+ completed.set(true);
+ }
+ catch (InvocationTargetException e) {
+ TestLoggerFactory.onTestFinished(false);
+ e.fillInStackTrace();
+ throwables[0] = e.getTargetException();
+ }
+ catch (IllegalAccessException e) {
+ TestLoggerFactory.onTestFinished(false);
+ e.fillInStackTrace();
+ throwables[0] = e;
+ }
+ catch (Throwable e) {
+ TestLoggerFactory.onTestFinished(false);
+ throwables[0] = e;
+ }
+ };
+
+ invokeTestRunnable(runnable);
+
+ if (throwables[0] != null) {
+ throw throwables[0];
+ }
+ if (!completed.get()) {
+ throw new IllegalStateException("test didn't start");
+ }
+ }
+
+ protected boolean shouldRunTest() {
+ return TestFrameworkUtil.canRunTest(getClass());
+ }
+
+ protected void invokeTestRunnable(@NotNull Runnable runnable) throws Exception {
+ //IdeaTestExecutionPolicy policy = IdeaTestExecutionPolicy.current();
+ //if (policy != null && !policy.runInDispatchThread()) {
+ // runnable.run();
+ //}
+ //else {
+ EdtTestUtilKt.runInEdtAndWait(() -> {
+ runnable.run();
+ return null;
+ });
+ //}
+ }
+
+ private void defaultRunBare() throws Throwable {
+ Throwable exception = null;
+ try {
+ long setupStart = System.nanoTime();
+ setUp();
+ long setupCost = (System.nanoTime() - setupStart) / 1000000;
+ logPerClassCost(setupCost, TOTAL_SETUP_COST_MILLIS);
+
+ runTest();
+ }
+ catch (Throwable running) {
+ exception = running;
+ }
+ finally {
+ try {
+ long teardownStart = System.nanoTime();
+ tearDown();
+ long teardownCost = (System.nanoTime() - teardownStart) / 1000000;
+ logPerClassCost(teardownCost, TOTAL_TEARDOWN_COST_MILLIS);
+ }
+ catch (Throwable tearingDown) {
+ if (exception == null) exception = tearingDown;
+ else exception = new CompoundRuntimeException(Arrays.asList(exception, tearingDown));
+ }
+ }
+ if (exception != null) throw exception;
+ }
+
+ /**
+ * Logs the setup cost grouped by test fixture class (superclass of the current test class).
+ *
+ * @param cost setup cost in milliseconds
+ */
+ private void logPerClassCost(long cost, @NotNull Map<String, Long> costMap) {
+ Class<?> superclass = getClass().getSuperclass();
+ Long oldCost = costMap.get(superclass.getName());
+ long newCost = oldCost == null ? cost : oldCost + cost;
+ costMap.put(superclass.getName(), newCost);
+ }
+
+ @SuppressWarnings("UseOfSystemOutOrSystemErr")
+ static void logSetupTeardownCosts() {
+ System.out.println("Setup costs");
+ long totalSetup = 0;
+ for (Map.Entry<String, Long> entry : TOTAL_SETUP_COST_MILLIS.entrySet()) {
+ System.out.println(String.format(" %s: %d ms", entry.getKey(), entry.getValue()));
+ totalSetup += entry.getValue();
+ }
+ System.out.println("Teardown costs");
+ long totalTeardown = 0;
+ for (Map.Entry<String, Long> entry : TOTAL_TEARDOWN_COST_MILLIS.entrySet()) {
+ System.out.println(String.format(" %s: %d ms", entry.getKey(), entry.getValue()));
+ totalTeardown += entry.getValue();
+ }
+ System.out.println(String.format("Total overhead: setup %d ms, teardown %d ms", totalSetup, totalTeardown));
+ System.out.println(String.format("##teamcity[buildStatisticValue key='ideaTests.totalSetupMs' value='%d']", totalSetup));
+ System.out.println(String.format("##teamcity[buildStatisticValue key='ideaTests.totalTeardownMs' value='%d']", totalTeardown));
+ }
+
+ @Override
+ public void runBare() throws Throwable {
+ if (!shouldRunTest()) return;
+
+ if (runInDispatchThread()) {
+ TestRunnerUtil.replaceIdeEventQueueSafely();
+ com.intellij.testFramework.EdtTestUtil.runInEdtAndWait(this::defaultRunBare);
+ }
+ else {
+ defaultRunBare();
+ }
+ }
+
+ protected boolean runInDispatchThread() {
+ //IdeaTestExecutionPolicy policy = IdeaTestExecutionPolicy.current();
+ //if (policy != null) {
+ // return policy.runInDispatchThread();
+ //}
+ return true;
+ }
+
+ @NotNull
+ public static String toString(@NotNull Iterable<?> collection) {
+ if (!collection.iterator().hasNext()) {
+ return "<empty>";
+ }
+
+ final StringBuilder builder = new StringBuilder();
+ for (final Object o : collection) {
+ if (o instanceof THashSet) {
+ builder.append(new TreeSet<>((THashSet<?>)o));
+ }
+ else {
+ builder.append(o);
+ }
+ builder.append('\n');
+ }
+ return builder.toString();
+ }
+
+ @SafeVarargs
+ public static <T> void assertOrderedEquals(@NotNull T[] actual, @NotNull T... expected) {
+ assertOrderedEquals(Arrays.asList(actual), expected);
+ }
+
+ @SafeVarargs
+ public static <T> void assertOrderedEquals(@NotNull Iterable<? extends T> actual, @NotNull T... expected) {
+ assertOrderedEquals("", actual, expected);
+ }
+
+ public static void assertOrderedEquals(@NotNull byte[] actual, @NotNull byte[] expected) {
+ assertEquals(expected.length, actual.length);
+ for (int i = 0; i < actual.length; i++) {
+ byte a = actual[i];
+ byte e = expected[i];
+ assertEquals("not equals at index: "+i, e, a);
+ }
+ }
+
+ public static void assertOrderedEquals(@NotNull int[] actual, @NotNull int[] expected) {
+ if (actual.length != expected.length) {
+ fail("Expected size: "+expected.length+"; actual: "+actual.length+"\nexpected: "+Arrays.toString(expected)+"\nactual : "+Arrays.toString(actual));
+ }
+ for (int i = 0; i < actual.length; i++) {
+ int a = actual[i];
+ int e = expected[i];
+ assertEquals("not equals at index: "+i, e, a);
+ }
+ }
+
+ @SafeVarargs
+ public static <T> void assertOrderedEquals(@NotNull String errorMsg, @NotNull Iterable<? extends T> actual, @NotNull T... expected) {
+ assertOrderedEquals(errorMsg, actual, Arrays.asList(expected));
+ }
+
+ public static <T> void assertOrderedEquals(@NotNull Iterable<? extends T> actual, @NotNull Iterable<? extends T> expected) {
+ assertOrderedEquals("", actual, expected);
+ }
+
+ public static <T> void assertOrderedEquals(@NotNull String errorMsg,
+ @NotNull Iterable<? extends T> actual,
+ @NotNull Iterable<? extends T> expected) {
+ //noinspection unchecked
+ assertOrderedEquals(errorMsg, actual, expected, Equality.CANONICAL);
+ }
+
+ public static <T> void assertOrderedEquals(@NotNull String errorMsg,
+ @NotNull Iterable<? extends T> actual,
+ @NotNull Iterable<? extends T> expected,
+ @NotNull Equality<? super T> comparator) {
+ if (!equals(actual, expected, comparator)) {
+ String expectedString = toString(expected);
+ String actualString = toString(actual);
+ Assert.assertEquals(errorMsg, expectedString, actualString);
+ Assert.fail("Warning! 'toString' does not reflect the difference.\nExpected: " + expectedString + "\nActual: " + actualString);
+ }
+ }
+
+ private static <T> boolean equals(@NotNull Iterable<? extends T> a1,
+ @NotNull Iterable<? extends T> a2,
+ @NotNull Equality<? super T> comparator) {
+ Iterator<? extends T> it1 = a1.iterator();
+ Iterator<? extends T> it2 = a2.iterator();
+ while (it1.hasNext() || it2.hasNext()) {
+ if (!it1.hasNext() || !it2.hasNext()) return false;
+ if (!comparator.equals(it1.next(), it2.next())) return false;
+ }
+ return true;
+ }
+
+ @SafeVarargs
+ public static <T> void assertOrderedCollection(@NotNull T[] collection, @NotNull Consumer<T>... checkers) {
+ assertOrderedCollection(Arrays.asList(collection), checkers);
+ }
+
+ /**
+ * Checks {@code actual} contains same elements (in {@link #equals(Object)} meaning) as {@code expected} irrespective of their order
+ */
+ @SafeVarargs
+ public static <T> void assertSameElements(@NotNull T[] actual, @NotNull T... expected) {
+ assertSameElements(Arrays.asList(actual), expected);
+ }
+
+ /**
+ * Checks {@code actual} contains same elements (in {@link #equals(Object)} meaning) as {@code expected} irrespective of their order
+ */
+ @SafeVarargs
+ public static <T> void assertSameElements(@NotNull Collection<? extends T> actual, @NotNull T... expected) {
+ assertSameElements(actual, Arrays.asList(expected));
+ }
+
+ /**
+ * Checks {@code actual} contains same elements (in {@link #equals(Object)} meaning) as {@code expected} irrespective of their order
+ */
+ public static <T> void assertSameElements(@NotNull Collection<? extends T> actual, @NotNull Collection<? extends T> expected) {
+ assertSameElements("", actual, expected);
+ }
+
+ /**
+ * Checks {@code actual} contains same elements (in {@link #equals(Object)} meaning) as {@code expected} irrespective of their order
+ */
+ public static <T> void assertSameElements(@NotNull String message, @NotNull Collection<? extends T> actual, @NotNull Collection<? extends T> expected) {
+ if (actual.size() != expected.size() || !new HashSet<>(expected).equals(new HashSet<T>(actual))) {
+ Assert.assertEquals(message, new HashSet<>(expected), new HashSet<T>(actual));
+ }
+ }
+
+ @SafeVarargs
+ public static <T> void assertContainsOrdered(@NotNull Collection<? extends T> collection, @NotNull T... expected) {
+ assertContainsOrdered(collection, Arrays.asList(expected));
+ }
+
+ public static <T> void assertContainsOrdered(@NotNull Collection<? extends T> collection, @NotNull Collection<? extends T> expected) {
+ ArrayList<T> copy = new ArrayList<>(collection);
+ copy.retainAll(expected);
+ assertOrderedEquals(toString(collection), copy, expected);
+ }
+
+ @SafeVarargs
+ public static <T> void assertContainsElements(@NotNull Collection<? extends T> collection, @NotNull T... expected) {
+ assertContainsElements(collection, Arrays.asList(expected));
+ }
+
+ public static <T> void assertContainsElements(@NotNull Collection<? extends T> collection, @NotNull Collection<? extends T> expected) {
+ ArrayList<T> copy = new ArrayList<>(collection);
+ copy.retainAll(expected);
+ assertSameElements(toString(collection), copy, expected);
+ }
+
+ @NotNull
+ public static String toString(@NotNull Object[] collection, @NotNull String separator) {
+ return toString(Arrays.asList(collection), separator);
+ }
+
+ @SafeVarargs
+ public static <T> void assertDoesntContain(@NotNull Collection<? extends T> collection, @NotNull T... notExpected) {
+ assertDoesntContain(collection, Arrays.asList(notExpected));
+ }
+
+ public static <T> void assertDoesntContain(@NotNull Collection<? extends T> collection, @NotNull Collection<? extends T> notExpected) {
+ ArrayList<T> expected = new ArrayList<>(collection);
+ expected.removeAll(notExpected);
+ assertSameElements(collection, expected);
+ }
+
+ @NotNull
+ public static String toString(@NotNull Collection<?> collection, @NotNull String separator) {
+ List<String> list = ContainerUtil.map2List(collection, String::valueOf);
+ Collections.sort(list);
+ StringBuilder builder = new StringBuilder();
+ boolean flag = false;
+ for (final String o : list) {
+ if (flag) {
+ builder.append(separator);
+ }
+ builder.append(o);
+ flag = true;
+ }
+ return builder.toString();
+ }
+
+ @SafeVarargs
+ public static <T> void assertOrderedCollection(@NotNull Collection<? extends T> collection, @NotNull Consumer<T>... checkers) {
+ if (collection.size() != checkers.length) {
+ Assert.fail(toString(collection));
+ }
+ int i = 0;
+ for (final T actual : collection) {
+ try {
+ checkers[i].consume(actual);
+ }
+ catch (AssertionFailedError e) {
+ //noinspection UseOfSystemOutOrSystemErr
+ System.out.println(i + ": " + actual);
+ throw e;
+ }
+ i++;
+ }
+ }
+
+ @SafeVarargs
+ public static <T> void assertUnorderedCollection(@NotNull T[] collection, @NotNull Consumer<T>... checkers) {
+ assertUnorderedCollection(Arrays.asList(collection), checkers);
+ }
+
+ @SafeVarargs
+ public static <T> void assertUnorderedCollection(@NotNull Collection<? extends T> collection, @NotNull Consumer<T>... checkers) {
+ if (collection.size() != checkers.length) {
+ Assert.fail(toString(collection));
+ }
+ Set<Consumer<T>> checkerSet = new HashSet<>(Arrays.asList(checkers));
+ int i = 0;
+ Throwable lastError = null;
+ for (final T actual : collection) {
+ boolean flag = true;
+ for (final Consumer<T> condition : checkerSet) {
+ Throwable error = accepts(condition, actual);
+ if (error == null) {
+ checkerSet.remove(condition);
+ flag = false;
+ break;
+ }
+ else {
+ lastError = error;
+ }
+ }
+ if (flag) {
+ //noinspection ConstantConditions,CallToPrintStackTrace
+ lastError.printStackTrace();
+ Assert.fail("Incorrect element(" + i + "): " + actual);
+ }
+ i++;
+ }
+ }
+
+ private static <T> Throwable accepts(@NotNull Consumer<? super T> condition, final T actual) {
+ try {
+ condition.consume(actual);
+ return null;
+ }
+ catch (Throwable e) {
+ return e;
+ }
+ }
+
+ @Contract("null, _ -> fail")
+ @NotNull
+ public static <T> T assertInstanceOf(Object o, @NotNull Class<T> aClass) {
+ Assert.assertNotNull("Expected instance of: " + aClass.getName() + " actual: " + null, o);
+ Assert.assertTrue("Expected instance of: " + aClass.getName() + " actual: " + o.getClass().getName(), aClass.isInstance(o));
+ @SuppressWarnings("unchecked") T t = (T)o;
+ return t;
+ }
+
+ public static <T> T assertOneElement(@NotNull Collection<? extends T> collection) {
+ Iterator<? extends T> iterator = collection.iterator();
+ String toString = toString(collection);
+ Assert.assertTrue(toString, iterator.hasNext());
+ T t = iterator.next();
+ Assert.assertFalse(toString, iterator.hasNext());
+ return t;
+ }
+
+ public static <T> T assertOneElement(@NotNull T[] ts) {
+ Assert.assertEquals(Arrays.asList(ts).toString(), 1, ts.length);
+ return ts[0];
+ }
+
+ @SafeVarargs
+ public static <T> void assertOneOf(T value, @NotNull T... values) {
+ for (T v : values) {
+ if (Objects.equals(value, v)) {
+ return;
+ }
+ }
+ Assert.fail(value + " should be equal to one of " + Arrays.toString(values));
+ }
+
+ public static void printThreadDump() {
+ PerformanceWatcher.dumpThreadsToConsole("Thread dump:");
+ }
+
+ public static void assertEmpty(@NotNull Object[] array) {
+ assertOrderedEquals(array);
+ }
+
+ public static void assertNotEmpty(final Collection<?> collection) {
+ assertNotNull(collection);
+ assertFalse(collection.isEmpty());
+ }
+
+ public static void assertEmpty(@NotNull Collection<?> collection) {
+ assertEmpty(collection.toString(), collection);
+ }
+
+ public static void assertNullOrEmpty(@Nullable Collection<?> collection) {
+ if (collection == null) return;
+ assertEmpty("", collection);
+ }
+
+ public static void assertEmpty(final String s) {
+ assertTrue(s, StringUtil.isEmpty(s));
+ }
+
+ public static <T> void assertEmpty(@NotNull String errorMsg, @NotNull Collection<? extends T> collection) {
+ assertOrderedEquals(errorMsg, collection, Collections.emptyList());
+ }
+
+ public static void assertSize(int expectedSize, @NotNull Object[] array) {
+ if (array.length != expectedSize) {
+ assertEquals(toString(Arrays.asList(array)), expectedSize, array.length);
+ }
+ }
+
+ public static void assertSize(int expectedSize, @NotNull Collection<?> c) {
+ if (c.size() != expectedSize) {
+ assertEquals(toString(c), expectedSize, c.size());
+ }
+ }
+
+ @NotNull
+ protected <T extends Disposable> T disposeOnTearDown(@NotNull T disposable) {
+ Disposer.register(getTestRootDisposable(), disposable);
+ return disposable;
+ }
+
+ public static void assertSameLines(@NotNull String expected, @NotNull String actual) {
+ assertSameLines(null, expected, actual);
+ }
+
+ public static void assertSameLines(@Nullable String message, @NotNull String expected, @NotNull String actual) {
+ String expectedText = StringUtil.convertLineSeparators(expected.trim());
+ String actualText = StringUtil.convertLineSeparators(actual.trim());
+ Assert.assertEquals(message, expectedText, actualText);
+ }
+
+ public static void assertExists(@NotNull File file){
+ assertTrue("File should exist " + file, file.exists());
+ }
+
+ public static void assertDoesntExist(@NotNull File file){
+ assertFalse("File should not exist " + file, file.exists());
+ }
+
+ @NotNull
+ protected String getTestName(boolean lowercaseFirstLetter) {
+ return getTestName(getName(), lowercaseFirstLetter);
+ }
+
+ @NotNull
+ public static String getTestName(@Nullable String name, boolean lowercaseFirstLetter) {
+ return name == null ? "" : PlatformTestUtil.getTestName(name, lowercaseFirstLetter);
+ }
+
+ @NotNull
+ protected String getTestDirectoryName() {
+ final String testName = getTestName(true);
+ return testName.replaceAll("_.*", "");
+ }
+
+ public static void assertSameLinesWithFile(@NotNull String filePath, @NotNull String actualText) {
+ assertSameLinesWithFile(filePath, actualText, true);
+ }
+
+ public static void assertSameLinesWithFile(@NotNull String filePath,
+ @NotNull String actualText,
+ @NotNull Supplier<String> messageProducer) {
+ assertSameLinesWithFile(filePath, actualText, true, messageProducer);
+ }
+
+ public static void assertSameLinesWithFile(@NotNull String filePath, @NotNull String actualText, boolean trimBeforeComparing) {
+ assertSameLinesWithFile(filePath, actualText, trimBeforeComparing, null);
+ }
+
+ public static void assertSameLinesWithFile(@NotNull String filePath,
+ @NotNull String actualText,
+ boolean trimBeforeComparing,
+ @Nullable Supplier<String> messageProducer) {
+ String fileText;
+ try {
+ if (OVERWRITE_TESTDATA) {
+ VfsTestUtil.overwriteTestData(filePath, actualText);
+ //noinspection UseOfSystemOutOrSystemErr
+ System.out.println("File " + filePath + " created.");
+ }
+ fileText = FileUtil.loadFile(new File(filePath), CharsetToolkit.UTF8_CHARSET);
+ }
+ catch (FileNotFoundException e) {
+ VfsTestUtil.overwriteTestData(filePath, actualText);
+ throw new AssertionFailedError("No output text found. File " + filePath + " created.");
+ }
+ catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ String expected = StringUtil.convertLineSeparators(trimBeforeComparing ? fileText.trim() : fileText);
+ String actual = StringUtil.convertLineSeparators(trimBeforeComparing ? actualText.trim() : actualText);
+ if (!Comparing.equal(expected, actual)) {
+ throw new FileComparisonFailure(messageProducer == null ? null : messageProducer.get(), expected, actual, filePath);
+ }
+ }
+
+ protected static void clearFields(@NotNull Object test) throws IllegalAccessException {
+ Class aClass = test.getClass();
+ while (aClass != null) {
+ clearDeclaredFields(test, aClass);
+ aClass = aClass.getSuperclass();
+ }
+ }
+
+ public static void clearDeclaredFields(@NotNull Object test, @NotNull Class aClass) throws IllegalAccessException {
+ for (final Field field : aClass.getDeclaredFields()) {
+ final String name = field.getDeclaringClass().getName();
+ if (!name.startsWith("junit.framework.") && !name.startsWith("com.intellij.testFramework.")) {
+ final int modifiers = field.getModifiers();
+ if ((modifiers & Modifier.FINAL) == 0 && (modifiers & Modifier.STATIC) == 0 && !field.getType().isPrimitive()) {
+ field.setAccessible(true);
+ field.set(test, null);
+ }
+ }
+ }
+ }
+
+ private static void checkCodeStyleSettingsEqual(@NotNull CodeStyleSettings expected, @NotNull CodeStyleSettings settings) {
+ if (!expected.equals(settings)) {
+ Element oldS = new Element("temp");
+ expected.writeExternal(oldS);
+ Element newS = new Element("temp");
+ settings.writeExternal(newS);
+
+ String newString = JDOMUtil.writeElement(newS);
+ String oldString = JDOMUtil.writeElement(oldS);
+ Assert.assertEquals("Code style settings damaged", oldString, newString);
+ }
+ }
+
+ public boolean isPerformanceTest() {
+ String testName = getName();
+ String className = getClass().getSimpleName();
+ return TestFrameworkUtil.isPerformanceTest(testName, className);
+ }
+
+ /**
+ * @return true for a test which performs A LOT of computations.
+ * Such test should typically avoid performing expensive checks, e.g. data structure consistency complex validations.
+ * If you want your test to be treated as "Stress", please mention one of these words in its name: "Stress", "Slow".
+ * For example: {@code public void testStressPSIFromDifferentThreads()}
+ */
+ public boolean isStressTest() {
+ return isStressTest(getName(), getClass().getName());
+ }
+
+ private static boolean isStressTest(String testName, String className) {
+ return TestFrameworkUtil.isPerformanceTest(testName, className) ||
+ containsStressWords(testName) ||
+ containsStressWords(className);
+ }
+
+ private static boolean containsStressWords(@Nullable String name) {
+ return name != null && (name.contains("Stress") || name.contains("Slow"));
+ }
+
+
+ /**
+ * Checks that code block throw corresponding exception with expected error msg.
+ * If expected error message is null it will not be checked.
+ *
+ * @param exceptionCase Block annotated with some exception type
+ * @param expectedErrorMsg expected error message
+ */
+ protected void assertException(@NotNull AbstractExceptionCase exceptionCase, @Nullable String expectedErrorMsg) {
+ //noinspection unchecked
+ assertExceptionOccurred(true, exceptionCase, expectedErrorMsg);
+ }
+
+ /**
+ * Checks that code block doesn't throw corresponding exception.
+ *
+ * @param exceptionCase Block annotated with some exception type
+ */
+ protected <T extends Throwable> void assertNoException(@NotNull AbstractExceptionCase<T> exceptionCase) throws T {
+ assertExceptionOccurred(false, exceptionCase, null);
+ }
+
+ protected void assertNoThrowable(@NotNull Runnable closure) {
+ String throwableName = null;
+ try {
+ closure.run();
+ }
+ catch (Throwable thr) {
+ throwableName = thr.getClass().getName();
+ }
+ assertNull(throwableName);
+ }
+
+ private static <T extends Throwable> void assertExceptionOccurred(boolean shouldOccur,
+ @NotNull AbstractExceptionCase<T> exceptionCase,
+ String expectedErrorMsg) throws T {
+ boolean wasThrown = false;
+ try {
+ exceptionCase.tryClosure();
+ }
+ catch (Throwable e) {
+ if (shouldOccur) {
+ wasThrown = true;
+ final String errorMessage = exceptionCase.getAssertionErrorMessage();
+ assertEquals(errorMessage, exceptionCase.getExpectedExceptionClass(), e.getClass());
+ if (expectedErrorMsg != null) {
+ assertEquals("Compare error messages", expectedErrorMsg, e.getMessage());
+ }
+ }
+ else if (exceptionCase.getExpectedExceptionClass().equals(e.getClass())) {
+ wasThrown = true;
+
+ //noinspection UseOfSystemOutOrSystemErr
+ System.out.println();
+ //noinspection UseOfSystemOutOrSystemErr
+ e.printStackTrace(System.out);
+
+ fail("Exception isn't expected here. Exception message: " + e.getMessage());
+ }
+ else {
+ throw e;
+ }
+ }
+ finally {
+ if (shouldOccur && !wasThrown) {
+ fail(exceptionCase.getAssertionErrorMessage());
+ }
+ }
+ }
+
+ protected boolean annotatedWith(@NotNull Class<? extends Annotation> annotationClass) {
+ Class<?> aClass = getClass();
+ String methodName = "test" + getTestName(false);
+ boolean methodChecked = false;
+ while (aClass != null && aClass != Object.class) {
+ if (aClass.getAnnotation(annotationClass) != null) return true;
+ if (!methodChecked) {
+ Method method = ReflectionUtil.getDeclaredMethod(aClass, methodName);
+ if (method != null) {
+ if (method.getAnnotation(annotationClass) != null) return true;
+ methodChecked = true;
+ }
+ }
+ aClass = aClass.getSuperclass();
+ }
+ return false;
+ }
+
+ @NotNull
+ protected String getHomePath() {
+ return PathManager.getHomePath().replace(File.separatorChar, '/');
+ }
+
+ public static void refreshRecursively(@NotNull VirtualFile file) {
+ VfsUtilCore.visitChildrenRecursively(file, new VirtualFileVisitor() {
+ @Override
+ public boolean visitFile(@NotNull VirtualFile file) {
+ file.getChildren();
+ return true;
+ }
+ });
+ file.refresh(false, true);
+ }
+
+ @Nullable
+ public static VirtualFile refreshAndFindFile(@NotNull final File file) {
+ return UIUtil.invokeAndWaitIfNeeded(() -> LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file));
+ }
+
+ protected class TestDisposable implements Disposable {
+ private volatile boolean myDisposed;
+
+ public TestDisposable() {
+ }
+
+ @Override
+ public void dispose() {
+ myDisposed = true;
+ }
+
+ public boolean isDisposed() {
+ return myDisposed;
+ }
+
+ @Override
+ public String toString() {
+ String testName = getTestName(false);
+ return KtUsefulTestCase.this.getClass() + (StringUtil.isEmpty(testName) ? "" : ".test" + testName);
+ }
+ };
+}
diff --git a/gradle/versions.properties b/gradle/versions.properties
index 0d985de..9ebc057 100644
--- a/gradle/versions.properties
+++ b/gradle/versions.properties
@@ -1,18 +1,18 @@
-versions.intellijSdk=193.6494.35
-versions.androidBuildTools=r23.0.1
-versions.idea.NodeJS=181.3494.12
-versions.jar.asm-all=7.0.1
-versions.jar.guava=27.1-jre
-versions.jar.groovy-all=2.4.17
-versions.jar.lombok-ast=0.2.3
-versions.jar.swingx-core=1.6.2-2
-versions.jar.kxml2=2.3.0
-versions.jar.streamex=0.6.8
-versions.jar.gson=2.8.5
-versions.jar.oro=2.0.8
-versions.jar.picocontainer=1.2
-versions.jar.serviceMessages=2019.1.4
-versions.jar.lz4-java=1.6.0
-ignore.jar.snappy-in-java=true
-versions.gradle-api=4.5.1
+versions.intellijSdk=201.5259.13-EAP-SNAPSHOT
+versions.androidBuildTools=r23.0.1
+versions.idea.NodeJS=193.6494.7
+versions.jar.asm-all=7.0.1
+versions.jar.guava=28.2-jre
+versions.jar.groovy-all=2.4.17
+versions.jar.lombok-ast=0.2.3
+versions.jar.swingx-core=1.6.2-2
+versions.jar.kxml2=2.3.0
+versions.jar.streamex=0.7.2
+versions.jar.gson=2.8.6
+versions.jar.oro=2.0.8
+versions.jar.picocontainer=1.2
+versions.jar.serviceMessages=2019.1.4
+versions.jar.lz4-java=1.7.1
+ignore.jar.snappy-in-java=true
+versions.gradle-api=4.5.1
versions.shadow=5.2.0
\ No newline at end of file
diff --git a/gradle/versions.properties.193 b/gradle/versions.properties.193
new file mode 100644
index 0000000..8fc0327
--- /dev/null
+++ b/gradle/versions.properties.193
@@ -0,0 +1,18 @@
+versions.intellijSdk=193.6494.35
+versions.androidBuildTools=r23.0.1
+versions.idea.NodeJS=181.3494.12
+versions.jar.asm-all=7.0.1
+versions.jar.guava=27.1-jre
+versions.jar.groovy-all=2.4.17
+versions.jar.lombok-ast=0.2.3
+versions.jar.swingx-core=1.6.2-2
+versions.jar.kxml2=2.3.0
+versions.jar.streamex=0.6.8
+versions.jar.gson=2.8.5
+versions.jar.oro=2.0.8
+versions.jar.picocontainer=1.2
+versions.jar.serviceMessages=2019.1.4
+versions.jar.lz4-java=1.6.0
+ignore.jar.snappy-in-java=true
+versions.gradle-api=4.5.1
+versions.shadow=5.2.0
\ No newline at end of file
diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/compat.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/compat.kt
index 081be02..4d283a4 100644
--- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/compat.kt
+++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/compat.kt
@@ -1,14 +1,14 @@
-/*
- * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
- * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
- */
-
-package org.jetbrains.kotlin.idea.caches
-
-import com.intellij.psi.PsiMethod
-import com.intellij.util.Processor
-
-// BUNCH 193
-typealias StringProcessor = Processor<String>
-typealias PsiMethodProcessor = Processor<PsiMethod>
-
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.caches
+
+import com.intellij.psi.PsiMethod
+import com.intellij.util.Processor
+
+// BUNCH 193
+typealias StringProcessor = Processor<in String>
+typealias PsiMethodProcessor = Processor<in PsiMethod>
+
diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/compat.kt.193 b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/compat.kt.193
new file mode 100644
index 0000000..57a39ac
--- /dev/null
+++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/compat.kt.193
@@ -0,0 +1,14 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.caches
+
+import com.intellij.psi.PsiMethod
+import com.intellij.util.Processor
+
+// BUNCH 193
+typealias StringProcessor = Processor<String>
+typealias PsiMethodProcessor = Processor<PsiMethod>
+
diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AnnotationPresentationInfo.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AnnotationPresentationInfo.kt
index 5ce9990..9653f24 100644
--- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AnnotationPresentationInfo.kt
+++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AnnotationPresentationInfo.kt
@@ -1,106 +1,98 @@
-/*
- * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
- * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
- */
-
-package org.jetbrains.kotlin.idea.highlighter
-
-import com.intellij.codeInsight.intention.EmptyIntentionAction
-import com.intellij.codeInsight.intention.IntentionAction
-import com.intellij.codeInspection.ProblemHighlightType
-import com.intellij.lang.annotation.Annotation
-import com.intellij.lang.annotation.AnnotationHolder
-import com.intellij.openapi.application.ApplicationManager
-import com.intellij.openapi.editor.colors.TextAttributesKey
-import com.intellij.openapi.util.TextRange
-import com.intellij.util.containers.MultiMap
-import com.intellij.xml.util.XmlStringUtil
-import org.jetbrains.kotlin.diagnostics.Diagnostic
-import org.jetbrains.kotlin.diagnostics.Severity
-import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages
-import org.jetbrains.kotlin.idea.inspections.KotlinUniversalQuickFix
-
-class AnnotationPresentationInfo(
- val ranges: List<TextRange>,
- val nonDefaultMessage: String? = null,
- val highlightType: ProblemHighlightType? = null,
- val textAttributes: TextAttributesKey? = null
-) {
-
- fun processDiagnostics(holder: AnnotationHolder, diagnostics: List<Diagnostic>, fixesMap: MultiMap<Diagnostic, IntentionAction>) {
- for (range in ranges) {
- for (diagnostic in diagnostics) {
- val fixes = fixesMap[diagnostic]
- val annotation = create(diagnostic, range, holder)
-
- fixes.forEach {
- when (it) {
- is KotlinUniversalQuickFix -> annotation.registerUniversalFix(it, null, null)
- is IntentionAction -> annotation.registerFix(it)
- }
- }
-
- if (diagnostic.severity == Severity.WARNING) {
- annotation.problemGroup = KotlinSuppressableWarningProblemGroup(diagnostic.factory)
-
- if (fixes.isEmpty()) {
- // if there are no quick fixes we need to register an EmptyIntentionAction to enable 'suppress' actions
- annotation.registerFix(EmptyIntentionAction(diagnostic.factory.name))
- }
- }
- }
- }
- }
-
- private fun create(diagnostic: Diagnostic, range: TextRange, holder: AnnotationHolder): Annotation {
- val defaultMessage = nonDefaultMessage ?: getDefaultMessage(diagnostic)
-
- val annotation = when (diagnostic.severity) {
- Severity.ERROR -> holder.createErrorAnnotation(range, defaultMessage)
- Severity.WARNING -> {
- if (highlightType == ProblemHighlightType.WEAK_WARNING) {
- holder.createWeakWarningAnnotation(range, defaultMessage)
- } else {
- holder.createWarningAnnotation(range, defaultMessage)
- }
- }
- Severity.INFO -> holder.createInfoAnnotation(range, defaultMessage)
- }
-
- annotation.tooltip = getMessage(diagnostic)
-
- if (highlightType != null) {
- annotation.highlightType = highlightType
- }
-
- if (textAttributes != null) {
- annotation.textAttributes = textAttributes
- }
-
- return annotation
- }
-
- private fun getMessage(diagnostic: Diagnostic): String {
- var message = IdeErrorMessages.render(diagnostic)
- if (ApplicationManager.getApplication().isInternal || ApplicationManager.getApplication().isUnitTestMode) {
- val factoryName = diagnostic.factory.name
- message = if (message.startsWith("<html>")) {
- "<html>[$factoryName] ${message.substring("<html>".length)}"
- } else {
- "[$factoryName] $message"
- }
- }
- if (!message.startsWith("<html>")) {
- message = "<html><body>${XmlStringUtil.escapeString(message)}</body></html>"
- }
- return message
- }
-
- private fun getDefaultMessage(diagnostic: Diagnostic): String {
- val message = DefaultErrorMessages.render(diagnostic)
- if (ApplicationManager.getApplication().isInternal || ApplicationManager.getApplication().isUnitTestMode) {
- return "[${diagnostic.factory.name}] $message"
- }
- return message
- }
-}
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.highlighter
+
+import com.intellij.codeInsight.intention.EmptyIntentionAction
+import com.intellij.codeInsight.intention.IntentionAction
+import com.intellij.codeInspection.ProblemHighlightType
+import com.intellij.lang.annotation.AnnotationBuilder
+import com.intellij.lang.annotation.AnnotationHolder
+import com.intellij.lang.annotation.HighlightSeverity
+import com.intellij.openapi.application.ApplicationManager
+import com.intellij.openapi.editor.colors.TextAttributesKey
+import com.intellij.openapi.util.TextRange
+import com.intellij.util.containers.MultiMap
+import com.intellij.xml.util.XmlStringUtil
+import org.jetbrains.kotlin.diagnostics.Diagnostic
+import org.jetbrains.kotlin.diagnostics.Severity
+import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages
+import org.jetbrains.kotlin.idea.inspections.KotlinUniversalQuickFix
+
+class AnnotationPresentationInfo(
+ val ranges: List<TextRange>,
+ val nonDefaultMessage: String? = null,
+ val highlightType: ProblemHighlightType? = null,
+ val textAttributes: TextAttributesKey? = null
+) {
+
+ fun processDiagnostics(holder: AnnotationHolder, diagnostics: List<Diagnostic>, fixesMap: MultiMap<Diagnostic, IntentionAction>) {
+ for (range in ranges) {
+ for (diagnostic in diagnostics) {
+ val fixes = fixesMap[diagnostic]
+ create(diagnostic, range, holder) { annotation ->
+ fixes.forEach {
+ when (it) {
+ is KotlinUniversalQuickFix -> annotation.newFix(it).universal().registerFix()
+ is IntentionAction -> annotation.newFix(it).registerFix()
+ }
+ }
+
+ if (diagnostic.severity == Severity.WARNING) {
+ annotation.problemGroup(KotlinSuppressableWarningProblemGroup(diagnostic.factory))
+
+ if (fixes.isEmpty()) {
+ // if there are no quick fixes we need to register an EmptyIntentionAction to enable 'suppress' actions
+ annotation.newFix(EmptyIntentionAction(diagnostic.factory.name)).registerFix()
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private fun create(diagnostic: Diagnostic, range: TextRange, holder: AnnotationHolder, consumer: (AnnotationBuilder) -> Unit) {
+ val severity = when (diagnostic.severity) {
+ Severity.ERROR -> HighlightSeverity.ERROR
+ Severity.WARNING -> if (highlightType == ProblemHighlightType.WEAK_WARNING) {
+ HighlightSeverity.WEAK_WARNING
+ } else HighlightSeverity.WARNING
+ Severity.INFO -> HighlightSeverity.WEAK_WARNING
+ }
+
+ holder.newAnnotation(severity, nonDefaultMessage ?: getDefaultMessage(diagnostic))
+ .range(range)
+ .tooltip(getMessage(diagnostic))
+ .also { builder -> highlightType?.let { builder.highlightType(it) } }
+ .also { builder -> textAttributes?.let { builder.textAttributes(it) } }
+ .also { consumer(it) }
+ .create()
+ }
+
+ private fun getMessage(diagnostic: Diagnostic): String {
+ var message = IdeErrorMessages.render(diagnostic)
+ if (ApplicationManager.getApplication().isInternal || ApplicationManager.getApplication().isUnitTestMode) {
+ val factoryName = diagnostic.factory.name
+ message = if (message.startsWith("<html>")) {
+ "<html>[$factoryName] ${message.substring("<html>".length)}"
+ } else {
+ "[$factoryName] $message"
+ }
+ }
+ if (!message.startsWith("<html>")) {
+ message = "<html><body>${XmlStringUtil.escapeString(message)}</body></html>"
+ }
+ return message
+ }
+
+ private fun getDefaultMessage(diagnostic: Diagnostic): String {
+ val message = DefaultErrorMessages.render(diagnostic)
+ if (ApplicationManager.getApplication().isInternal || ApplicationManager.getApplication().isUnitTestMode) {
+ return "[${diagnostic.factory.name}] $message"
+ }
+ return message
+ }
+
+}
diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AnnotationPresentationInfo.kt.193 b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AnnotationPresentationInfo.kt.193
new file mode 100644
index 0000000..e57cfd8
--- /dev/null
+++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/AnnotationPresentationInfo.kt.193
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.highlighter
+
+import com.intellij.codeInsight.intention.EmptyIntentionAction
+import com.intellij.codeInsight.intention.IntentionAction
+import com.intellij.codeInspection.ProblemHighlightType
+import com.intellij.lang.annotation.Annotation
+import com.intellij.lang.annotation.AnnotationHolder
+import com.intellij.openapi.application.ApplicationManager
+import com.intellij.openapi.editor.colors.TextAttributesKey
+import com.intellij.openapi.util.TextRange
+import com.intellij.util.containers.MultiMap
+import com.intellij.xml.util.XmlStringUtil
+import org.jetbrains.kotlin.diagnostics.Diagnostic
+import org.jetbrains.kotlin.diagnostics.Severity
+import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages
+import org.jetbrains.kotlin.idea.inspections.KotlinUniversalQuickFix
+
+class AnnotationPresentationInfo(
+ val ranges: List<TextRange>,
+ val nonDefaultMessage: String? = null,
+ val highlightType: ProblemHighlightType? = null,
+ val textAttributes: TextAttributesKey? = null
+) {
+
+ fun processDiagnostics(holder: AnnotationHolder, diagnostics: List<Diagnostic>, fixesMap: MultiMap<Diagnostic, IntentionAction>) {
+ for (range in ranges) {
+ for (diagnostic in diagnostics) {
+ val fixes = fixesMap[diagnostic]
+ val annotation = create(diagnostic, range, holder)
+
+ fixes.forEach {
+ when (it) {
+ is KotlinUniversalQuickFix -> annotation.registerUniversalFix(it, null, null)
+ is IntentionAction -> annotation.registerFix(it)
+ }
+ }
+
+ if (diagnostic.severity == Severity.WARNING) {
+ annotation.problemGroup = KotlinSuppressableWarningProblemGroup(diagnostic.factory)
+
+ if (fixes.isEmpty()) {
+ // if there are no quick fixes we need to register an EmptyIntentionAction to enable 'suppress' actions
+ annotation.registerFix(EmptyIntentionAction(diagnostic.factory.name))
+ }
+ }
+ }
+ }
+ }
+
+ private fun create(diagnostic: Diagnostic, range: TextRange, holder: AnnotationHolder): Annotation {
+ val defaultMessage = nonDefaultMessage ?: getDefaultMessage(diagnostic)
+
+ val annotation = when (diagnostic.severity) {
+ Severity.ERROR -> holder.createErrorAnnotation(range, defaultMessage)
+ Severity.WARNING -> {
+ if (highlightType == ProblemHighlightType.WEAK_WARNING) {
+ holder.createWeakWarningAnnotation(range, defaultMessage)
+ } else {
+ holder.createWarningAnnotation(range, defaultMessage)
+ }
+ }
+ Severity.INFO -> holder.createInfoAnnotation(range, defaultMessage)
+ }
+
+ annotation.tooltip = getMessage(diagnostic)
+
+ if (highlightType != null) {
+ annotation.highlightType = highlightType
+ }
+
+ if (textAttributes != null) {
+ annotation.textAttributes = textAttributes
+ }
+
+ return annotation
+ }
+
+ private fun getMessage(diagnostic: Diagnostic): String {
+ var message = IdeErrorMessages.render(diagnostic)
+ if (ApplicationManager.getApplication().isInternal || ApplicationManager.getApplication().isUnitTestMode) {
+ val factoryName = diagnostic.factory.name
+ message = if (message.startsWith("<html>")) {
+ "<html>[$factoryName] ${message.substring("<html>".length)}"
+ } else {
+ "[$factoryName] $message"
+ }
+ }
+ if (!message.startsWith("<html>")) {
+ message = "<html><body>${XmlStringUtil.escapeString(message)}</body></html>"
+ }
+ return message
+ }
+
+ private fun getDefaultMessage(diagnostic: Diagnostic): String {
+ val message = DefaultErrorMessages.render(diagnostic)
+ if (ApplicationManager.getApplication().isInternal || ApplicationManager.getApplication().isUnitTestMode) {
+ return "[${diagnostic.factory.name}] $message"
+ }
+ return message
+ }
+}
diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/modules/ModuleHighlightUtil2.java b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/modules/ModuleHighlightUtil2.java
index 053f070..0dd8070 100644
--- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/modules/ModuleHighlightUtil2.java
+++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/modules/ModuleHighlightUtil2.java
@@ -1,114 +1,114 @@
-/*
- * Copyright 2010-2017 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.jetbrains.kotlin.idea.modules;
-
-import com.intellij.openapi.module.Module;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.roots.ModuleRootManager;
-import com.intellij.openapi.roots.ProjectFileIndex;
-import com.intellij.openapi.vfs.JarFileSystem;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.psi.PsiFile;
-import com.intellij.psi.PsiJavaFile;
-import com.intellij.psi.PsiJavaModule;
-import com.intellij.psi.PsiManager;
-import com.intellij.psi.impl.light.LightJavaModule;
-import kotlin.collections.ArraysKt;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-import org.jetbrains.kotlin.idea.core.FileIndexUtilsKt;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.jar.Attributes;
-import java.util.jar.JarFile;
-import java.util.jar.Manifest;
-
-import static com.intellij.psi.PsiJavaModule.MODULE_INFO_FILE;
-
-// Copied from com.intellij.codeInsight.daemon.impl.analysis.ModuleHighlightUtil
-public class ModuleHighlightUtil2 {
- private static final Attributes.Name MULTI_RELEASE = new Attributes.Name("Multi-Release");
-
- @Nullable
- static PsiJavaModule getModuleDescriptor(@NotNull VirtualFile file, @NotNull Project project) {
- ProjectFileIndex index = ProjectFileIndex.SERVICE.getInstance(project);
- if (index.isInLibrary(file)) {
- VirtualFile root;
- if ((root = index.getClassRootForFile(file)) != null) {
- VirtualFile descriptorFile = root.findChild(PsiJavaModule.MODULE_INFO_CLS_FILE);
- if (descriptorFile == null) {
- VirtualFile alt = root.findFileByRelativePath("META-INF/versions/9/" + PsiJavaModule.MODULE_INFO_CLS_FILE);
- if (alt != null && isMultiReleaseJar(root)) {
- descriptorFile = alt;
- }
- }
- if (descriptorFile != null) {
- PsiFile psiFile = PsiManager.getInstance(project).findFile(descriptorFile);
- if (psiFile instanceof PsiJavaFile) {
- return ((PsiJavaFile) psiFile).getModuleDeclaration();
- }
- }
- else if (root.getFileSystem() instanceof JarFileSystem && "jar".equalsIgnoreCase(root.getExtension())) {
- return LightJavaModule.getModule(PsiManager.getInstance(project), root);
- }
- }
- else if ((root = index.getSourceRootForFile(file)) != null) {
- VirtualFile descriptorFile = root.findChild(MODULE_INFO_FILE);
- if (descriptorFile != null) {
- PsiFile psiFile = PsiManager.getInstance(project).findFile(descriptorFile);
- if (psiFile instanceof PsiJavaFile) {
- return ((PsiJavaFile) psiFile).getModuleDeclaration();
- }
- }
- }
- }
- else {
- Module module = index.getModuleForFile(file);
- if (module != null) {
- boolean isTest = FileIndexUtilsKt.isInTestSourceContentKotlinAware(index, file);
- VirtualFile modularRoot = ArraysKt.singleOrNull(ModuleRootManager.getInstance(module).getSourceRoots(isTest),
- root -> root.findChild(MODULE_INFO_FILE) != null);
- if (modularRoot != null) {
- VirtualFile moduleInfo = modularRoot.findChild(MODULE_INFO_FILE);
- assert moduleInfo != null : modularRoot;
- PsiFile psiFile = PsiManager.getInstance(project).findFile(moduleInfo);
- if (psiFile instanceof PsiJavaFile) {
- return ((PsiJavaFile) psiFile).getModuleDeclaration();
- }
- }
- }
- }
-
- return null;
- }
-
- private static boolean isMultiReleaseJar(VirtualFile root) {
- if (root.getFileSystem() instanceof JarFileSystem) {
- VirtualFile manifest = root.findFileByRelativePath(JarFile.MANIFEST_NAME);
- if (manifest != null) {
- try (InputStream stream = manifest.getInputStream()) {
- return Boolean.valueOf(new Manifest(stream).getMainAttributes().getValue(MULTI_RELEASE));
- }
- catch (IOException ignored) {
- }
- }
- }
-
- return false;
- }
-}
+/*
+ * Copyright 2010-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlin.idea.modules;
+
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.ModuleRootManager;
+import com.intellij.openapi.roots.ProjectFileIndex;
+import com.intellij.openapi.vfs.JarFileSystem;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiJavaFile;
+import com.intellij.psi.PsiJavaModule;
+import com.intellij.psi.PsiManager;
+import com.intellij.psi.impl.light.LightJavaModule;
+import kotlin.collections.ArraysKt;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.kotlin.idea.core.FileIndexUtilsKt;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.jar.Attributes;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+
+import static com.intellij.psi.PsiJavaModule.MODULE_INFO_FILE;
+
+// Copied from com.intellij.codeInsight.daemon.impl.analysis.ModuleHighlightUtil
+public class ModuleHighlightUtil2 {
+ private static final Attributes.Name MULTI_RELEASE = new Attributes.Name("Multi-Release");
+
+ @Nullable
+ static PsiJavaModule getModuleDescriptor(@NotNull VirtualFile file, @NotNull Project project) {
+ ProjectFileIndex index = ProjectFileIndex.SERVICE.getInstance(project);
+ if (index.isInLibrary(file)) {
+ VirtualFile root;
+ if ((root = index.getClassRootForFile(file)) != null) {
+ VirtualFile descriptorFile = root.findChild(PsiJavaModule.MODULE_INFO_CLS_FILE);
+ if (descriptorFile == null) {
+ VirtualFile alt = root.findFileByRelativePath("META-INF/versions/9/" + PsiJavaModule.MODULE_INFO_CLS_FILE);
+ if (alt != null && isMultiReleaseJar(root)) {
+ descriptorFile = alt;
+ }
+ }
+ if (descriptorFile != null) {
+ PsiFile psiFile = PsiManager.getInstance(project).findFile(descriptorFile);
+ if (psiFile instanceof PsiJavaFile) {
+ return ((PsiJavaFile) psiFile).getModuleDeclaration();
+ }
+ }
+ else if (root.getFileSystem() instanceof JarFileSystem && "jar".equalsIgnoreCase(root.getExtension())) {
+ return LightJavaModule.findModule(PsiManager.getInstance(project), root);
+ }
+ }
+ else if ((root = index.getSourceRootForFile(file)) != null) {
+ VirtualFile descriptorFile = root.findChild(MODULE_INFO_FILE);
+ if (descriptorFile != null) {
+ PsiFile psiFile = PsiManager.getInstance(project).findFile(descriptorFile);
+ if (psiFile instanceof PsiJavaFile) {
+ return ((PsiJavaFile) psiFile).getModuleDeclaration();
+ }
+ }
+ }
+ }
+ else {
+ Module module = index.getModuleForFile(file);
+ if (module != null) {
+ boolean isTest = FileIndexUtilsKt.isInTestSourceContentKotlinAware(index, file);
+ VirtualFile modularRoot = ArraysKt.singleOrNull(ModuleRootManager.getInstance(module).getSourceRoots(isTest),
+ root -> root.findChild(MODULE_INFO_FILE) != null);
+ if (modularRoot != null) {
+ VirtualFile moduleInfo = modularRoot.findChild(MODULE_INFO_FILE);
+ assert moduleInfo != null : modularRoot;
+ PsiFile psiFile = PsiManager.getInstance(project).findFile(moduleInfo);
+ if (psiFile instanceof PsiJavaFile) {
+ return ((PsiJavaFile) psiFile).getModuleDeclaration();
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private static boolean isMultiReleaseJar(VirtualFile root) {
+ if (root.getFileSystem() instanceof JarFileSystem) {
+ VirtualFile manifest = root.findFileByRelativePath(JarFile.MANIFEST_NAME);
+ if (manifest != null) {
+ try (InputStream stream = manifest.getInputStream()) {
+ return Boolean.valueOf(new Manifest(stream).getMainAttributes().getValue(MULTI_RELEASE));
+ }
+ catch (IOException ignored) {
+ }
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/modules/ModuleHighlightUtil2.java.193 b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/modules/ModuleHighlightUtil2.java.193
new file mode 100644
index 0000000..e0a7283
--- /dev/null
+++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/modules/ModuleHighlightUtil2.java.193
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2010-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlin.idea.modules;
+
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.ModuleRootManager;
+import com.intellij.openapi.roots.ProjectFileIndex;
+import com.intellij.openapi.vfs.JarFileSystem;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiJavaFile;
+import com.intellij.psi.PsiJavaModule;
+import com.intellij.psi.PsiManager;
+import com.intellij.psi.impl.light.LightJavaModule;
+import kotlin.collections.ArraysKt;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.kotlin.idea.core.FileIndexUtilsKt;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.jar.Attributes;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+
+import static com.intellij.psi.PsiJavaModule.MODULE_INFO_FILE;
+
+// Copied from com.intellij.codeInsight.daemon.impl.analysis.ModuleHighlightUtil
+public class ModuleHighlightUtil2 {
+ private static final Attributes.Name MULTI_RELEASE = new Attributes.Name("Multi-Release");
+
+ @Nullable
+ static PsiJavaModule getModuleDescriptor(@NotNull VirtualFile file, @NotNull Project project) {
+ ProjectFileIndex index = ProjectFileIndex.SERVICE.getInstance(project);
+ if (index.isInLibrary(file)) {
+ VirtualFile root;
+ if ((root = index.getClassRootForFile(file)) != null) {
+ VirtualFile descriptorFile = root.findChild(PsiJavaModule.MODULE_INFO_CLS_FILE);
+ if (descriptorFile == null) {
+ VirtualFile alt = root.findFileByRelativePath("META-INF/versions/9/" + PsiJavaModule.MODULE_INFO_CLS_FILE);
+ if (alt != null && isMultiReleaseJar(root)) {
+ descriptorFile = alt;
+ }
+ }
+ if (descriptorFile != null) {
+ PsiFile psiFile = PsiManager.getInstance(project).findFile(descriptorFile);
+ if (psiFile instanceof PsiJavaFile) {
+ return ((PsiJavaFile) psiFile).getModuleDeclaration();
+ }
+ }
+ else if (root.getFileSystem() instanceof JarFileSystem && "jar".equalsIgnoreCase(root.getExtension())) {
+ return LightJavaModule.getModule(PsiManager.getInstance(project), root);
+ }
+ }
+ else if ((root = index.getSourceRootForFile(file)) != null) {
+ VirtualFile descriptorFile = root.findChild(MODULE_INFO_FILE);
+ if (descriptorFile != null) {
+ PsiFile psiFile = PsiManager.getInstance(project).findFile(descriptorFile);
+ if (psiFile instanceof PsiJavaFile) {
+ return ((PsiJavaFile) psiFile).getModuleDeclaration();
+ }
+ }
+ }
+ }
+ else {
+ Module module = index.getModuleForFile(file);
+ if (module != null) {
+ boolean isTest = FileIndexUtilsKt.isInTestSourceContentKotlinAware(index, file);
+ VirtualFile modularRoot = ArraysKt.singleOrNull(ModuleRootManager.getInstance(module).getSourceRoots(isTest),
+ root -> root.findChild(MODULE_INFO_FILE) != null);
+ if (modularRoot != null) {
+ VirtualFile moduleInfo = modularRoot.findChild(MODULE_INFO_FILE);
+ assert moduleInfo != null : modularRoot;
+ PsiFile psiFile = PsiManager.getInstance(project).findFile(moduleInfo);
+ if (psiFile instanceof PsiJavaFile) {
+ return ((PsiJavaFile) psiFile).getModuleDeclaration();
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private static boolean isMultiReleaseJar(VirtualFile root) {
+ if (root.getFileSystem() instanceof JarFileSystem) {
+ VirtualFile manifest = root.findFileByRelativePath(JarFile.MANIFEST_NAME);
+ if (manifest != null) {
+ try (InputStream stream = manifest.getInputStream()) {
+ return Boolean.valueOf(new Manifest(stream).getMainAttributes().getValue(MULTI_RELEASE));
+ }
+ catch (IOException ignored) {
+ }
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/util/ApplicationUtils.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/util/ApplicationUtils.kt
index c46694d..f1fff27 100644
--- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/util/ApplicationUtils.kt
+++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/util/ApplicationUtils.kt
@@ -1,46 +1,47 @@
-/*
- * Copyright 2010-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 org.jetbrains.kotlin.idea.util.application
-
-import com.intellij.openapi.application.ApplicationManager
-import com.intellij.openapi.command.CommandProcessor
-import com.intellij.openapi.project.Project
-
-fun <T> runReadAction(action: () -> T): T {
- return ApplicationManager.getApplication().runReadAction<T>(action)
-}
-
-fun <T> runWriteAction(action: () -> T): T {
- return ApplicationManager.getApplication().runWriteAction<T>(action)
-}
-
-fun Project.executeWriteCommand(name: String, command: () -> Unit) {
- CommandProcessor.getInstance().executeCommand(this, { runWriteAction(command) }, name, null)
-}
-
-fun <T> Project.executeWriteCommand(name: String, groupId: Any? = null, command: () -> T): T {
- return executeCommand<T>(name, groupId) { runWriteAction(command) }
-}
-
-fun <T> Project.executeCommand(name: String, groupId: Any? = null, command: () -> T): T {
- @Suppress("UNCHECKED_CAST") var result: T = null as T
- CommandProcessor.getInstance().executeCommand(this, { result = command() }, name, groupId)
- @Suppress("USELESS_CAST")
- return result as T
-}
-
-fun <T> runWithCancellationCheck(block: () -> T): T = block()
\ No newline at end of file
+/*
+ * Copyright 2010-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 org.jetbrains.kotlin.idea.util.application
+
+import com.intellij.openapi.application.ApplicationManager
+import com.intellij.openapi.command.CommandProcessor
+import com.intellij.openapi.progress.impl.CancellationCheck
+import com.intellij.openapi.project.Project
+
+fun <T> runReadAction(action: () -> T): T {
+ return ApplicationManager.getApplication().runReadAction<T>(action)
+}
+
+fun <T> runWriteAction(action: () -> T): T {
+ return ApplicationManager.getApplication().runWriteAction<T>(action)
+}
+
+fun Project.executeWriteCommand(name: String, command: () -> Unit) {
+ CommandProcessor.getInstance().executeCommand(this, { runWriteAction(command) }, name, null)
+}
+
+fun <T> Project.executeWriteCommand(name: String, groupId: Any? = null, command: () -> T): T {
+ return executeCommand<T>(name, groupId) { runWriteAction(command) }
+}
+
+fun <T> Project.executeCommand(name: String, groupId: Any? = null, command: () -> T): T {
+ @Suppress("UNCHECKED_CAST") var result: T = null as T
+ CommandProcessor.getInstance().executeCommand(this, { result = command() }, name, groupId)
+ @Suppress("USELESS_CAST")
+ return result as T
+}
+
+fun <T> runWithCancellationCheck(block: () -> T): T = CancellationCheck.runWithCancellationCheck(block)
\ No newline at end of file
diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/util/ApplicationUtils.kt.193 b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/util/ApplicationUtils.kt.193
new file mode 100644
index 0000000..b0bfd84
--- /dev/null
+++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/util/ApplicationUtils.kt.193
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2010-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 org.jetbrains.kotlin.idea.util.application
+
+import com.intellij.openapi.application.ApplicationManager
+import com.intellij.openapi.command.CommandProcessor
+import com.intellij.openapi.project.Project
+
+fun <T> runReadAction(action: () -> T): T {
+ return ApplicationManager.getApplication().runReadAction<T>(action)
+}
+
+fun <T> runWriteAction(action: () -> T): T {
+ return ApplicationManager.getApplication().runWriteAction<T>(action)
+}
+
+fun Project.executeWriteCommand(name: String, command: () -> Unit) {
+ CommandProcessor.getInstance().executeCommand(this, { runWriteAction(command) }, name, null)
+}
+
+fun <T> Project.executeWriteCommand(name: String, groupId: Any? = null, command: () -> T): T {
+ return executeCommand<T>(name, groupId) { runWriteAction(command) }
+}
+
+fun <T> Project.executeCommand(name: String, groupId: Any? = null, command: () -> T): T {
+ @Suppress("UNCHECKED_CAST") var result: T = null as T
+ CommandProcessor.getInstance().executeCommand(this, { result = command() }, name, groupId)
+ @Suppress("USELESS_CAST")
+ return result as T
+}
+
+fun <T> runWithCancellationCheck(block: () -> T): T = block()
\ No newline at end of file
diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/compat.kt b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/compat.kt
index 3189682..fcd6288 100644
--- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/compat.kt
+++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/compat.kt
@@ -1,13 +1,14 @@
-/*
- * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
- * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
- */
-
-package org.jetbrains.kotlin.idea.completion.test.handlers
-
-import com.intellij.codeInsight.lookup.impl.LookupImpl
-
-// BUNCH: 193
-fun LookupImpl.setFocusedFocusDegree() {
- focusDegree = LookupImpl.FocusDegree.FOCUSED
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.completion.test.handlers
+
+import com.intellij.codeInsight.lookup.LookupFocusDegree
+import com.intellij.codeInsight.lookup.impl.LookupImpl
+
+// BUNCH: 193
+fun LookupImpl.setFocusedFocusDegree() {
+ this.lookupFocusDegree = LookupFocusDegree.FOCUSED
}
\ No newline at end of file
diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/compat.kt.193 b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/compat.kt.193
new file mode 100644
index 0000000..57567d6
--- /dev/null
+++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/compat.kt.193
@@ -0,0 +1,13 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.completion.test.handlers
+
+import com.intellij.codeInsight.lookup.impl.LookupImpl
+
+// BUNCH: 193
+fun LookupImpl.setFocusedFocusDegree() {
+ focusDegree = LookupImpl.FocusDegree.FOCUSED
+}
\ No newline at end of file
diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/AbstractProjectResolverExtensionCompat.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/AbstractProjectResolverExtensionCompat.kt
index f6f8ea9..cf7074f 100644
--- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/AbstractProjectResolverExtensionCompat.kt
+++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/AbstractProjectResolverExtensionCompat.kt
@@ -1,28 +1,28 @@
-/*
- * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
- * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
- */
-
-package org.jetbrains.kotlin.idea.configuration
-
-import com.intellij.openapi.externalSystem.model.DataNode
-import com.intellij.openapi.externalSystem.model.project.ModuleData
-import com.intellij.openapi.externalSystem.model.project.ProjectData
-import org.gradle.tooling.model.idea.IdeaModule
-import org.jetbrains.plugins.gradle.service.project.AbstractProjectResolverExtension
-
-// BUNCH: 193
-abstract class AbstractProjectResolverExtensionCompat : AbstractProjectResolverExtension() {
- override fun createModule(gradleModule: IdeaModule, projectDataNode: DataNode<ProjectData>): DataNode<ModuleData> {
- return super.createModule(gradleModule, projectDataNode).also {
- initializeModuleNode(gradleModule, it, projectDataNode)
- }
- }
-
- // Inline after class remove
- abstract fun initializeModuleNode(
- gradleModule: IdeaModule,
- moduleDataNode: DataNode<ModuleData>,
- projectDataNode: DataNode<ProjectData>,
- )
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.configuration
+
+import com.intellij.openapi.externalSystem.model.DataNode
+import com.intellij.openapi.externalSystem.model.project.ModuleData
+import com.intellij.openapi.externalSystem.model.project.ProjectData
+import org.gradle.tooling.model.idea.IdeaModule
+import org.jetbrains.plugins.gradle.service.project.AbstractProjectResolverExtension
+
+// BUNCH: 193
+abstract class AbstractProjectResolverExtensionCompat : AbstractProjectResolverExtension() {
+ override fun createModule(gradleModule: IdeaModule, projectDataNode: DataNode<ProjectData>): DataNode<ModuleData>? {
+ return super.createModule(gradleModule, projectDataNode)?.also {
+ initializeModuleNode(gradleModule, it, projectDataNode)
+ }
+ }
+
+ // Inline after class remove
+ abstract fun initializeModuleNode(
+ gradleModule: IdeaModule,
+ moduleDataNode: DataNode<ModuleData>,
+ projectDataNode: DataNode<ProjectData>,
+ )
}
\ No newline at end of file
diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/AbstractProjectResolverExtensionCompat.kt.193 b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/AbstractProjectResolverExtensionCompat.kt.193
new file mode 100644
index 0000000..d2ce09f
--- /dev/null
+++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/AbstractProjectResolverExtensionCompat.kt.193
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.configuration
+
+import com.intellij.openapi.externalSystem.model.DataNode
+import com.intellij.openapi.externalSystem.model.project.ModuleData
+import com.intellij.openapi.externalSystem.model.project.ProjectData
+import org.gradle.tooling.model.idea.IdeaModule
+import org.jetbrains.plugins.gradle.service.project.AbstractProjectResolverExtension
+
+// BUNCH: 193
+abstract class AbstractProjectResolverExtensionCompat : AbstractProjectResolverExtension() {
+ override fun createModule(gradleModule: IdeaModule, projectDataNode: DataNode<ProjectData>): DataNode<ModuleData> {
+ return super.createModule(gradleModule, projectDataNode).also {
+ initializeModuleNode(gradleModule, it, projectDataNode)
+ }
+ }
+
+ // Inline after class remove
+ abstract fun initializeModuleNode(
+ gradleModule: IdeaModule,
+ moduleDataNode: DataNode<ModuleData>,
+ projectDataNode: DataNode<ProjectData>,
+ )
+}
\ No newline at end of file
diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/AsyncFileChangeListenerHelper.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/AsyncFileChangeListenerHelper.kt
index 342b8d7..829fea2 100644
--- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/AsyncFileChangeListenerHelper.kt
+++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/AsyncFileChangeListenerHelper.kt
@@ -1,32 +1,31 @@
-/*
- * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
- * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
- */
-
-package org.jetbrains.kotlin.idea.scripting.gradle
-
-import com.intellij.openapi.externalSystem.service.project.autoimport.AsyncFileChangeListenerBase
-import com.intellij.openapi.vfs.VirtualFile
-import com.intellij.openapi.vfs.VirtualFileManager
-import com.intellij.openapi.vfs.newvfs.events.VFileEvent
-
-fun addVfsListener(watcher: GradleScriptInputsWatcher) {
- VirtualFileManager.getInstance().addAsyncFileListener(
- object : AsyncFileChangeListenerBase() {
- override fun isRelevant(path: String): Boolean {
- return isInAffectedGradleProjectFiles(watcher.project, path)
- }
-
- override fun updateFile(file: VirtualFile, event: VFileEvent) {
- watcher.fileChanged(event.path, file.timeStamp)
- }
-
- // do nothing
- override fun prepareFileDeletion(file: VirtualFile) {}
- override fun apply() {}
- override fun reset() {}
-
- },
- watcher.project
- )
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.scripting.gradle
+
+import com.intellij.openapi.externalSystem.autoimport.AsyncFileChangeListenerBase
+import com.intellij.openapi.vfs.VirtualFile
+import com.intellij.openapi.vfs.VirtualFileManager
+import com.intellij.openapi.vfs.newvfs.events.VFileEvent
+
+fun addVfsListener(watcher: GradleScriptInputsWatcher) {
+ VirtualFileManager.getInstance().addAsyncFileListener(
+ object : AsyncFileChangeListenerBase() {
+ override fun isRelevant(path: String): Boolean {
+ return isInAffectedGradleProjectFiles(watcher.project, path)
+ }
+
+ override fun updateFile(file: VirtualFile, event: VFileEvent) {
+ watcher.fileChanged(event.path, file.timeStamp)
+ }
+
+ // do nothing
+ override fun apply() {}
+ override fun init() {}
+
+ },
+ watcher.project
+ )
}
\ No newline at end of file
diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/AsyncFileChangeListenerHelper.kt.193 b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/AsyncFileChangeListenerHelper.kt.193
new file mode 100644
index 0000000..ec9a3d4
--- /dev/null
+++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/scripting/gradle/AsyncFileChangeListenerHelper.kt.193
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.scripting.gradle
+
+import com.intellij.openapi.externalSystem.service.project.autoimport.AsyncFileChangeListenerBase
+import com.intellij.openapi.vfs.VirtualFile
+import com.intellij.openapi.vfs.VirtualFileManager
+import com.intellij.openapi.vfs.newvfs.events.VFileEvent
+
+fun addVfsListener(watcher: GradleScriptInputsWatcher) {
+ VirtualFileManager.getInstance().addAsyncFileListener(
+ object : AsyncFileChangeListenerBase() {
+ override fun isRelevant(path: String): Boolean {
+ return isInAffectedGradleProjectFiles(watcher.project, path)
+ }
+
+ override fun updateFile(file: VirtualFile, event: VFileEvent) {
+ watcher.fileChanged(event.path, file.timeStamp)
+ }
+
+ // do nothing
+ override fun prepareFileDeletion(file: VirtualFile) {}
+ override fun apply() {}
+ override fun reset() {}
+
+ },
+ watcher.project
+ )
+}
\ No newline at end of file
diff --git a/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/AbstractModelBuilderTest.java b/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/AbstractModelBuilderTest.java
index b473aa5..5f2e316 100644
--- a/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/AbstractModelBuilderTest.java
+++ b/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/AbstractModelBuilderTest.java
@@ -1,233 +1,233 @@
-/*
- * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
- * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
- */
-package org.jetbrains.kotlin.idea.codeInsight.gradle;
-
-import com.google.common.collect.Multimap;
-import com.intellij.openapi.util.io.FileUtil;
-import com.intellij.openapi.util.io.StreamUtil;
-import com.intellij.testFramework.IdeaTestUtil;
-import com.intellij.util.containers.ContainerUtil;
-import org.codehaus.groovy.runtime.typehandling.ShortTypeHandling;
-import org.gradle.tooling.BuildActionExecuter;
-import org.gradle.tooling.GradleConnector;
-import org.gradle.tooling.ProjectConnection;
-import org.gradle.tooling.internal.consumer.DefaultGradleConnector;
-import org.gradle.util.GradleVersion;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.plugins.gradle.model.ClassSetProjectImportModelProvider;
-import org.jetbrains.plugins.gradle.model.ExternalProject;
-import org.jetbrains.plugins.gradle.model.ProjectImportAction;
-import org.jetbrains.plugins.gradle.service.execution.GradleExecutionHelper;
-import org.jetbrains.plugins.gradle.tooling.builder.ModelBuildScriptClasspathBuilderImpl;
-import org.jetbrains.plugins.gradle.util.GradleConstants;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.rules.TestName;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assume.assumeThat;
-
-// part of org.jetbrains.plugins.gradle.tooling.builder.AbstractModelBuilderTest
-@RunWith(value = Parameterized.class)
-public abstract class AbstractModelBuilderTest {
-
- public static final Object[][] SUPPORTED_GRADLE_VERSIONS = {{"4.9"}, {"5.6.4"}};
-
- private static final Pattern TEST_METHOD_NAME_PATTERN = Pattern.compile("(.*)\\[(\\d*: with Gradle-.*)\\]");
-
- private static File ourTempDir;
-
- @NotNull
- private final String gradleVersion;
- private File testDir;
- private ProjectImportAction.AllModels allModels;
-
- @Rule public TestName name = new TestName();
- @Rule public VersionMatcherRule versionMatcherRule = new VersionMatcherRule();
-
- public AbstractModelBuilderTest(@NotNull String gradleVersion) {
- this.gradleVersion = gradleVersion;
- }
-
- @Parameterized.Parameters(name = "{index}: with Gradle-{0}")
- public static Collection<Object[]> data() {
- return Arrays.asList(SUPPORTED_GRADLE_VERSIONS);
- }
-
-
- @Before
- public void setUp() throws Exception {
- assumeThat(gradleVersion, versionMatcherRule.getMatcher());
-
- ensureTempDirCreated();
-
- String methodName = name.getMethodName();
- Matcher m = TEST_METHOD_NAME_PATTERN.matcher(methodName);
- if (m.matches()) {
- methodName = m.group(1);
- }
-
- testDir = new File(ourTempDir, methodName);
- FileUtil.ensureExists(testDir);
-
- InputStream buildScriptStream = getClass().getResourceAsStream("/" + methodName + "/" + GradleConstants.DEFAULT_SCRIPT_NAME);
- try {
- FileUtil.writeToFile(
- new File(testDir, GradleConstants.DEFAULT_SCRIPT_NAME),
- FileUtil.loadTextAndClose(buildScriptStream)
- );
- }
- finally {
- StreamUtil.closeStream(buildScriptStream);
- }
-
- InputStream settingsStream = getClass().getResourceAsStream("/" + methodName + "/" + GradleConstants.SETTINGS_FILE_NAME);
- try {
- if (settingsStream != null) {
- FileUtil.writeToFile(
- new File(testDir, GradleConstants.SETTINGS_FILE_NAME),
- FileUtil.loadTextAndClose(settingsStream)
- );
- }
- }
- finally {
- StreamUtil.closeStream(settingsStream);
- }
-
- GradleConnector connector = GradleConnector.newConnector();
-
- URI distributionUri = new DistributionLocator().getDistributionFor(GradleVersion.version(gradleVersion));
- connector.useDistribution(distributionUri);
- connector.forProjectDirectory(testDir);
- int daemonMaxIdleTime = 10;
- try {
- daemonMaxIdleTime = Integer.parseInt(System.getProperty("gradleDaemonMaxIdleTime", "10"));
- }
- catch (NumberFormatException ignore) {
- }
-
- ((DefaultGradleConnector) connector).daemonMaxIdleTime(daemonMaxIdleTime, TimeUnit.SECONDS);
- ProjectConnection connection = connector.connect();
-
- try {
- ProjectImportAction projectImportAction = new ProjectImportAction(false);
- projectImportAction.addProjectImportModelProvider(new ClassSetProjectImportModelProvider(getModels()));
- BuildActionExecuter<ProjectImportAction.AllModels> buildActionExecutor = connection.action(projectImportAction);
- File initScript = GradleExecutionHelper.generateInitScript(false, getToolingExtensionClasses());
- assertNotNull(initScript);
- String jdkHome = IdeaTestUtil.requireRealJdkHome();
- buildActionExecutor.setJavaHome(new File(jdkHome));
- buildActionExecutor.setJvmArguments("-Xmx128m", "-XX:MaxPermSize=64m");
- buildActionExecutor
- .withArguments("--info", "--recompile-scripts", GradleConstants.INIT_SCRIPT_CMD_OPTION, initScript.getAbsolutePath());
- allModels = buildActionExecutor.run();
- assertNotNull(allModels);
- }
- finally {
- connection.close();
- }
- }
-
- @NotNull
- private static Set<Class> getToolingExtensionClasses() {
- Set<Class> classes = ContainerUtil.<Class>set(
- ExternalProject.class,
- // gradle-tooling-extension-api jar
- ProjectImportAction.class,
- // gradle-tooling-extension-impl jar
- ModelBuildScriptClasspathBuilderImpl.class,
- Multimap.class,
- ShortTypeHandling.class
- );
-
- ContainerUtil.addAllNotNull(classes, doGetToolingExtensionClasses());
- return classes;
- }
-
- @NotNull
- private static Set<Class> doGetToolingExtensionClasses() {
- return Collections.emptySet();
- }
-
- @After
- public void tearDown() throws Exception {
- if (testDir != null) {
- FileUtil.delete(testDir);
- }
- }
-
- protected abstract Set<Class> getModels();
-
-
- private static void ensureTempDirCreated() throws IOException {
- if (ourTempDir != null) return;
-
- ourTempDir = new File(FileUtil.getTempDirectory(), "gradleTests");
- FileUtil.delete(ourTempDir);
- FileUtil.ensureExists(ourTempDir);
- }
-
- public static class DistributionLocator {
- private static final String RELEASE_REPOSITORY_ENV = "GRADLE_RELEASE_REPOSITORY";
- private static final String SNAPSHOT_REPOSITORY_ENV = "GRADLE_SNAPSHOT_REPOSITORY";
- private static final String GRADLE_RELEASE_REPO = "https://services.gradle.org/distributions";
- private static final String GRADLE_SNAPSHOT_REPO = "https://services.gradle.org/distributions-snapshots";
-
- @NotNull private final String myReleaseRepoUrl;
- @NotNull private final String mySnapshotRepoUrl;
-
- public DistributionLocator() {
- this(DistributionLocator.getRepoUrl(false), DistributionLocator.getRepoUrl(true));
- }
-
- public DistributionLocator(@NotNull String releaseRepoUrl, @NotNull String snapshotRepoUrl) {
- myReleaseRepoUrl = releaseRepoUrl;
- mySnapshotRepoUrl = snapshotRepoUrl;
- }
-
- @NotNull
- public URI getDistributionFor(@NotNull GradleVersion version) throws URISyntaxException {
- return getDistribution(getDistributionRepository(version), version, "gradle", "bin");
- }
-
- @NotNull
- private String getDistributionRepository(@NotNull GradleVersion version) {
- return version.isSnapshot() ? mySnapshotRepoUrl : myReleaseRepoUrl;
- }
-
- private static URI getDistribution(
- @NotNull String repositoryUrl,
- @NotNull GradleVersion version,
- @NotNull String archiveName,
- @NotNull String archiveClassifier
- ) throws URISyntaxException {
- return new URI(String.format("%s/%s-%s-%s.zip", repositoryUrl, archiveName, version.getVersion(), archiveClassifier));
- }
-
- @NotNull
- public static String getRepoUrl(boolean isSnapshotUrl) {
- String envRepoUrl = System.getenv(isSnapshotUrl ? SNAPSHOT_REPOSITORY_ENV : RELEASE_REPOSITORY_ENV);
- if (envRepoUrl != null) return envRepoUrl;
-
- return isSnapshotUrl ? GRADLE_SNAPSHOT_REPO : GRADLE_RELEASE_REPO;
- }
- }
-}
+/*
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+package org.jetbrains.kotlin.idea.codeInsight.gradle;
+
+import com.google.common.collect.Multimap;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.util.io.StreamUtil;
+import com.intellij.testFramework.IdeaTestUtil;
+import com.intellij.util.containers.ContainerUtil;
+import org.codehaus.groovy.runtime.typehandling.ShortTypeHandling;
+import org.gradle.tooling.BuildActionExecuter;
+import org.gradle.tooling.GradleConnector;
+import org.gradle.tooling.ProjectConnection;
+import org.gradle.tooling.internal.consumer.DefaultGradleConnector;
+import org.gradle.util.GradleVersion;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.plugins.gradle.model.ClassSetProjectImportModelProvider;
+import org.jetbrains.plugins.gradle.model.ExternalProject;
+import org.jetbrains.plugins.gradle.model.ProjectImportAction;
+import org.jetbrains.plugins.gradle.service.execution.GradleExecutionHelper;
+import org.jetbrains.plugins.gradle.tooling.builder.ModelBuildScriptClasspathBuilderImpl;
+import org.jetbrains.plugins.gradle.util.GradleConstants;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.rules.TestName;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assume.assumeThat;
+
+// part of org.jetbrains.plugins.gradle.tooling.builder.AbstractModelBuilderTest
+@RunWith(value = Parameterized.class)
+public abstract class AbstractModelBuilderTest {
+
+ public static final Object[][] SUPPORTED_GRADLE_VERSIONS = {{"4.9"}, {"5.6.4"}};
+
+ private static final Pattern TEST_METHOD_NAME_PATTERN = Pattern.compile("(.*)\\[(\\d*: with Gradle-.*)\\]");
+
+ private static File ourTempDir;
+
+ @NotNull
+ private final String gradleVersion;
+ private File testDir;
+ private ProjectImportAction.AllModels allModels;
+
+ @Rule public TestName name = new TestName();
+ @Rule public VersionMatcherRule versionMatcherRule = new VersionMatcherRule();
+
+ public AbstractModelBuilderTest(@NotNull String gradleVersion) {
+ this.gradleVersion = gradleVersion;
+ }
+
+ @Parameterized.Parameters(name = "{index}: with Gradle-{0}")
+ public static Collection<Object[]> data() {
+ return Arrays.asList(SUPPORTED_GRADLE_VERSIONS);
+ }
+
+
+ @Before
+ public void setUp() throws Exception {
+ assumeThat(gradleVersion, versionMatcherRule.getMatcher());
+
+ ensureTempDirCreated();
+
+ String methodName = name.getMethodName();
+ Matcher m = TEST_METHOD_NAME_PATTERN.matcher(methodName);
+ if (m.matches()) {
+ methodName = m.group(1);
+ }
+
+ testDir = new File(ourTempDir, methodName);
+ FileUtil.ensureExists(testDir);
+
+ InputStream buildScriptStream = getClass().getResourceAsStream("/" + methodName + "/" + GradleConstants.DEFAULT_SCRIPT_NAME);
+ try {
+ FileUtil.writeToFile(
+ new File(testDir, GradleConstants.DEFAULT_SCRIPT_NAME),
+ FileUtil.loadTextAndClose(buildScriptStream)
+ );
+ }
+ finally {
+ StreamUtil.closeStream(buildScriptStream);
+ }
+
+ InputStream settingsStream = getClass().getResourceAsStream("/" + methodName + "/" + GradleConstants.SETTINGS_FILE_NAME);
+ try {
+ if (settingsStream != null) {
+ FileUtil.writeToFile(
+ new File(testDir, GradleConstants.SETTINGS_FILE_NAME),
+ FileUtil.loadTextAndClose(settingsStream)
+ );
+ }
+ }
+ finally {
+ StreamUtil.closeStream(settingsStream);
+ }
+
+ GradleConnector connector = GradleConnector.newConnector();
+
+ URI distributionUri = new DistributionLocator().getDistributionFor(GradleVersion.version(gradleVersion));
+ connector.useDistribution(distributionUri);
+ connector.forProjectDirectory(testDir);
+ int daemonMaxIdleTime = 10;
+ try {
+ daemonMaxIdleTime = Integer.parseInt(System.getProperty("gradleDaemonMaxIdleTime", "10"));
+ }
+ catch (NumberFormatException ignore) {
+ }
+
+ ((DefaultGradleConnector) connector).daemonMaxIdleTime(daemonMaxIdleTime, TimeUnit.SECONDS);
+ ProjectConnection connection = connector.connect();
+
+ try {
+ ProjectImportAction projectImportAction = new ProjectImportAction(false);
+ projectImportAction.addProjectImportModelProvider(new ClassSetProjectImportModelProvider(getModels()));
+ BuildActionExecuter<ProjectImportAction.AllModels> buildActionExecutor = connection.action(projectImportAction);
+ File initScript = GradleExecutionHelper.generateInitScript(false, getToolingExtensionClasses());
+ assertNotNull(initScript);
+ String jdkHome = IdeaTestUtil.requireRealJdkHome();
+ buildActionExecutor.setJavaHome(new File(jdkHome));
+ buildActionExecutor.setJvmArguments("-Xmx128m", "-XX:MaxPermSize=64m");
+ buildActionExecutor
+ .withArguments("--info", "--recompile-scripts", GradleConstants.INIT_SCRIPT_CMD_OPTION, initScript.getAbsolutePath());
+ allModels = buildActionExecutor.run();
+ assertNotNull(allModels);
+ }
+ finally {
+ connection.close();
+ }
+ }
+
+ @NotNull
+ private static Set<Class<?>> getToolingExtensionClasses() {
+ Set<Class<?>> classes = ContainerUtil.set(
+ ExternalProject.class,
+ // gradle-tooling-extension-api jar
+ ProjectImportAction.class,
+ // gradle-tooling-extension-impl jar
+ ModelBuildScriptClasspathBuilderImpl.class,
+ Multimap.class,
+ ShortTypeHandling.class
+ );
+
+ ContainerUtil.addAllNotNull(classes, doGetToolingExtensionClasses());
+ return classes;
+ }
+
+ @NotNull
+ private static Set<Class<?>> doGetToolingExtensionClasses() {
+ return Collections.emptySet();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ if (testDir != null) {
+ FileUtil.delete(testDir);
+ }
+ }
+
+ protected abstract Set<Class<?>> getModels();
+
+
+ private static void ensureTempDirCreated() throws IOException {
+ if (ourTempDir != null) return;
+
+ ourTempDir = new File(FileUtil.getTempDirectory(), "gradleTests");
+ FileUtil.delete(ourTempDir);
+ FileUtil.ensureExists(ourTempDir);
+ }
+
+ public static class DistributionLocator {
+ private static final String RELEASE_REPOSITORY_ENV = "GRADLE_RELEASE_REPOSITORY";
+ private static final String SNAPSHOT_REPOSITORY_ENV = "GRADLE_SNAPSHOT_REPOSITORY";
+ private static final String GRADLE_RELEASE_REPO = "https://services.gradle.org/distributions";
+ private static final String GRADLE_SNAPSHOT_REPO = "https://services.gradle.org/distributions-snapshots";
+
+ @NotNull private final String myReleaseRepoUrl;
+ @NotNull private final String mySnapshotRepoUrl;
+
+ public DistributionLocator() {
+ this(DistributionLocator.getRepoUrl(false), DistributionLocator.getRepoUrl(true));
+ }
+
+ public DistributionLocator(@NotNull String releaseRepoUrl, @NotNull String snapshotRepoUrl) {
+ myReleaseRepoUrl = releaseRepoUrl;
+ mySnapshotRepoUrl = snapshotRepoUrl;
+ }
+
+ @NotNull
+ public URI getDistributionFor(@NotNull GradleVersion version) throws URISyntaxException {
+ return getDistribution(getDistributionRepository(version), version, "gradle", "bin");
+ }
+
+ @NotNull
+ private String getDistributionRepository(@NotNull GradleVersion version) {
+ return version.isSnapshot() ? mySnapshotRepoUrl : myReleaseRepoUrl;
+ }
+
+ private static URI getDistribution(
+ @NotNull String repositoryUrl,
+ @NotNull GradleVersion version,
+ @NotNull String archiveName,
+ @NotNull String archiveClassifier
+ ) throws URISyntaxException {
+ return new URI(String.format("%s/%s-%s-%s.zip", repositoryUrl, archiveName, version.getVersion(), archiveClassifier));
+ }
+
+ @NotNull
+ public static String getRepoUrl(boolean isSnapshotUrl) {
+ String envRepoUrl = System.getenv(isSnapshotUrl ? SNAPSHOT_REPOSITORY_ENV : RELEASE_REPOSITORY_ENV);
+ if (envRepoUrl != null) return envRepoUrl;
+
+ return isSnapshotUrl ? GRADLE_SNAPSHOT_REPO : GRADLE_RELEASE_REPO;
+ }
+ }
+}
diff --git a/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/AbstractModelBuilderTest.java.193 b/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/AbstractModelBuilderTest.java.193
new file mode 100644
index 0000000..0d08c70
--- /dev/null
+++ b/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/AbstractModelBuilderTest.java.193
@@ -0,0 +1,233 @@
+/*
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+package org.jetbrains.kotlin.idea.codeInsight.gradle;
+
+import com.google.common.collect.Multimap;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.util.io.StreamUtil;
+import com.intellij.testFramework.IdeaTestUtil;
+import com.intellij.util.containers.ContainerUtil;
+import org.codehaus.groovy.runtime.typehandling.ShortTypeHandling;
+import org.gradle.tooling.BuildActionExecuter;
+import org.gradle.tooling.GradleConnector;
+import org.gradle.tooling.ProjectConnection;
+import org.gradle.tooling.internal.consumer.DefaultGradleConnector;
+import org.gradle.util.GradleVersion;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.plugins.gradle.model.ClassSetProjectImportModelProvider;
+import org.jetbrains.plugins.gradle.model.ExternalProject;
+import org.jetbrains.plugins.gradle.model.ProjectImportAction;
+import org.jetbrains.plugins.gradle.service.execution.GradleExecutionHelper;
+import org.jetbrains.plugins.gradle.tooling.builder.ModelBuildScriptClasspathBuilderImpl;
+import org.jetbrains.plugins.gradle.util.GradleConstants;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.rules.TestName;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assume.assumeThat;
+
+// part of org.jetbrains.plugins.gradle.tooling.builder.AbstractModelBuilderTest
+@RunWith(value = Parameterized.class)
+public abstract class AbstractModelBuilderTest {
+
+ public static final Object[][] SUPPORTED_GRADLE_VERSIONS = {{"4.9"}, {"5.6.4"}};
+
+ private static final Pattern TEST_METHOD_NAME_PATTERN = Pattern.compile("(.*)\\[(\\d*: with Gradle-.*)\\]");
+
+ private static File ourTempDir;
+
+ @NotNull
+ private final String gradleVersion;
+ private File testDir;
+ private ProjectImportAction.AllModels allModels;
+
+ @Rule public TestName name = new TestName();
+ @Rule public VersionMatcherRule versionMatcherRule = new VersionMatcherRule();
+
+ public AbstractModelBuilderTest(@NotNull String gradleVersion) {
+ this.gradleVersion = gradleVersion;
+ }
+
+ @Parameterized.Parameters(name = "{index}: with Gradle-{0}")
+ public static Collection<Object[]> data() {
+ return Arrays.asList(SUPPORTED_GRADLE_VERSIONS);
+ }
+
+
+ @Before
+ public void setUp() throws Exception {
+ assumeThat(gradleVersion, versionMatcherRule.getMatcher());
+
+ ensureTempDirCreated();
+
+ String methodName = name.getMethodName();
+ Matcher m = TEST_METHOD_NAME_PATTERN.matcher(methodName);
+ if (m.matches()) {
+ methodName = m.group(1);
+ }
+
+ testDir = new File(ourTempDir, methodName);
+ FileUtil.ensureExists(testDir);
+
+ InputStream buildScriptStream = getClass().getResourceAsStream("/" + methodName + "/" + GradleConstants.DEFAULT_SCRIPT_NAME);
+ try {
+ FileUtil.writeToFile(
+ new File(testDir, GradleConstants.DEFAULT_SCRIPT_NAME),
+ FileUtil.loadTextAndClose(buildScriptStream)
+ );
+ }
+ finally {
+ StreamUtil.closeStream(buildScriptStream);
+ }
+
+ InputStream settingsStream = getClass().getResourceAsStream("/" + methodName + "/" + GradleConstants.SETTINGS_FILE_NAME);
+ try {
+ if (settingsStream != null) {
+ FileUtil.writeToFile(
+ new File(testDir, GradleConstants.SETTINGS_FILE_NAME),
+ FileUtil.loadTextAndClose(settingsStream)
+ );
+ }
+ }
+ finally {
+ StreamUtil.closeStream(settingsStream);
+ }
+
+ GradleConnector connector = GradleConnector.newConnector();
+
+ URI distributionUri = new DistributionLocator().getDistributionFor(GradleVersion.version(gradleVersion));
+ connector.useDistribution(distributionUri);
+ connector.forProjectDirectory(testDir);
+ int daemonMaxIdleTime = 10;
+ try {
+ daemonMaxIdleTime = Integer.parseInt(System.getProperty("gradleDaemonMaxIdleTime", "10"));
+ }
+ catch (NumberFormatException ignore) {
+ }
+
+ ((DefaultGradleConnector) connector).daemonMaxIdleTime(daemonMaxIdleTime, TimeUnit.SECONDS);
+ ProjectConnection connection = connector.connect();
+
+ try {
+ ProjectImportAction projectImportAction = new ProjectImportAction(false);
+ projectImportAction.addProjectImportModelProvider(new ClassSetProjectImportModelProvider(getModels()));
+ BuildActionExecuter<ProjectImportAction.AllModels> buildActionExecutor = connection.action(projectImportAction);
+ File initScript = GradleExecutionHelper.generateInitScript(false, getToolingExtensionClasses());
+ assertNotNull(initScript);
+ String jdkHome = IdeaTestUtil.requireRealJdkHome();
+ buildActionExecutor.setJavaHome(new File(jdkHome));
+ buildActionExecutor.setJvmArguments("-Xmx128m", "-XX:MaxPermSize=64m");
+ buildActionExecutor
+ .withArguments("--info", "--recompile-scripts", GradleConstants.INIT_SCRIPT_CMD_OPTION, initScript.getAbsolutePath());
+ allModels = buildActionExecutor.run();
+ assertNotNull(allModels);
+ }
+ finally {
+ connection.close();
+ }
+ }
+
+ @NotNull
+ private static Set<Class> getToolingExtensionClasses() {
+ Set<Class> classes = ContainerUtil.<Class>set(
+ ExternalProject.class,
+ // gradle-tooling-extension-api jar
+ ProjectImportAction.class,
+ // gradle-tooling-extension-impl jar
+ ModelBuildScriptClasspathBuilderImpl.class,
+ Multimap.class,
+ ShortTypeHandling.class
+ );
+
+ ContainerUtil.addAllNotNull(classes, doGetToolingExtensionClasses());
+ return classes;
+ }
+
+ @NotNull
+ private static Set<Class> doGetToolingExtensionClasses() {
+ return Collections.emptySet();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ if (testDir != null) {
+ FileUtil.delete(testDir);
+ }
+ }
+
+ protected abstract Set<Class> getModels();
+
+
+ private static void ensureTempDirCreated() throws IOException {
+ if (ourTempDir != null) return;
+
+ ourTempDir = new File(FileUtil.getTempDirectory(), "gradleTests");
+ FileUtil.delete(ourTempDir);
+ FileUtil.ensureExists(ourTempDir);
+ }
+
+ public static class DistributionLocator {
+ private static final String RELEASE_REPOSITORY_ENV = "GRADLE_RELEASE_REPOSITORY";
+ private static final String SNAPSHOT_REPOSITORY_ENV = "GRADLE_SNAPSHOT_REPOSITORY";
+ private static final String GRADLE_RELEASE_REPO = "https://services.gradle.org/distributions";
+ private static final String GRADLE_SNAPSHOT_REPO = "https://services.gradle.org/distributions-snapshots";
+
+ @NotNull private final String myReleaseRepoUrl;
+ @NotNull private final String mySnapshotRepoUrl;
+
+ public DistributionLocator() {
+ this(DistributionLocator.getRepoUrl(false), DistributionLocator.getRepoUrl(true));
+ }
+
+ public DistributionLocator(@NotNull String releaseRepoUrl, @NotNull String snapshotRepoUrl) {
+ myReleaseRepoUrl = releaseRepoUrl;
+ mySnapshotRepoUrl = snapshotRepoUrl;
+ }
+
+ @NotNull
+ public URI getDistributionFor(@NotNull GradleVersion version) throws URISyntaxException {
+ return getDistribution(getDistributionRepository(version), version, "gradle", "bin");
+ }
+
+ @NotNull
+ private String getDistributionRepository(@NotNull GradleVersion version) {
+ return version.isSnapshot() ? mySnapshotRepoUrl : myReleaseRepoUrl;
+ }
+
+ private static URI getDistribution(
+ @NotNull String repositoryUrl,
+ @NotNull GradleVersion version,
+ @NotNull String archiveName,
+ @NotNull String archiveClassifier
+ ) throws URISyntaxException {
+ return new URI(String.format("%s/%s-%s-%s.zip", repositoryUrl, archiveName, version.getVersion(), archiveClassifier));
+ }
+
+ @NotNull
+ public static String getRepoUrl(boolean isSnapshotUrl) {
+ String envRepoUrl = System.getenv(isSnapshotUrl ? SNAPSHOT_REPOSITORY_ENV : RELEASE_REPOSITORY_ENV);
+ if (envRepoUrl != null) return envRepoUrl;
+
+ return isSnapshotUrl ? GRADLE_SNAPSHOT_REPO : GRADLE_RELEASE_REPO;
+ }
+ }
+}
diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/actions/ShowKotlinBytecodeAction.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/actions/ShowKotlinBytecodeAction.kt
index b51fbde..edb7a8e 100644
--- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/actions/ShowKotlinBytecodeAction.kt
+++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/actions/ShowKotlinBytecodeAction.kt
@@ -1,52 +1,54 @@
-/*
- * Copyright 2010-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 org.jetbrains.kotlin.idea.actions
-
-import com.intellij.openapi.actionSystem.AnAction
-import com.intellij.openapi.actionSystem.AnActionEvent
-import com.intellij.openapi.actionSystem.CommonDataKeys
-import com.intellij.openapi.wm.ToolWindowAnchor
-import com.intellij.openapi.wm.ToolWindowManager
-import com.intellij.ui.content.ContentFactory
-import org.jetbrains.kotlin.idea.KotlinFileType
-import org.jetbrains.kotlin.idea.KotlinIcons
-import org.jetbrains.kotlin.idea.internal.KotlinBytecodeToolWindow
-
-class ShowKotlinBytecodeAction : AnAction() {
- val TOOLWINDOW_ID = "Kotlin Bytecode"
-
- override fun actionPerformed(e: AnActionEvent) {
- val project = e.project ?: return
- val toolWindowManager = ToolWindowManager.getInstance(project)
-
- var toolWindow = toolWindowManager.getToolWindow(TOOLWINDOW_ID)
- if (toolWindow == null) {
- toolWindow = toolWindowManager.registerToolWindow("Kotlin Bytecode", false, ToolWindowAnchor.RIGHT)
- toolWindow.icon = KotlinIcons.SMALL_LOGO_13
-
- val contentManager = toolWindow.contentManager
- val contentFactory = ContentFactory.SERVICE.getInstance()
- contentManager.addContent(contentFactory.createContent(KotlinBytecodeToolWindow(project, toolWindow), "", false))
- }
- toolWindow.activate(null)
- }
-
- override fun update(e: AnActionEvent) {
- val file = e.getData(CommonDataKeys.PSI_FILE)
- e.presentation.isEnabled = e.project != null && file?.fileType == KotlinFileType.INSTANCE
- }
-}
+/*
+ * Copyright 2010-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 org.jetbrains.kotlin.idea.actions
+
+import com.intellij.openapi.actionSystem.AnAction
+import com.intellij.openapi.actionSystem.AnActionEvent
+import com.intellij.openapi.actionSystem.CommonDataKeys
+import com.intellij.openapi.wm.ToolWindowAnchor
+import com.intellij.openapi.wm.ToolWindowManager
+import com.intellij.ui.content.ContentFactory
+import org.jetbrains.kotlin.idea.KotlinFileType
+import org.jetbrains.kotlin.idea.KotlinIcons
+import org.jetbrains.kotlin.idea.internal.KotlinBytecodeToolWindow
+
+class ShowKotlinBytecodeAction : AnAction() {
+ val TOOLWINDOW_ID = "Kotlin Bytecode"
+
+ override fun actionPerformed(e: AnActionEvent) {
+ val project = e.project ?: return
+ val toolWindowManager = ToolWindowManager.getInstance(project)
+
+ val toolWindow = toolWindowManager.getToolWindow(TOOLWINDOW_ID) ?: toolWindowManager.registerToolWindow(
+ "Kotlin Bytecode",
+ false,
+ ToolWindowAnchor.RIGHT,
+ )
+ .apply {
+ setIcon(KotlinIcons.SMALL_LOGO_13)
+ val contentFactory = ContentFactory.SERVICE.getInstance()
+ contentManager.addContent(contentFactory.createContent(KotlinBytecodeToolWindow(project, this), "", false))
+ }
+
+ toolWindow.activate(null)
+ }
+
+ override fun update(e: AnActionEvent) {
+ val file = e.getData(CommonDataKeys.PSI_FILE)
+ e.presentation.isEnabled = e.project != null && file?.fileType == KotlinFileType.INSTANCE
+ }
+}
diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/actions/ShowKotlinBytecodeAction.kt.193 b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/actions/ShowKotlinBytecodeAction.kt.193
new file mode 100644
index 0000000..b61a7a0
--- /dev/null
+++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/actions/ShowKotlinBytecodeAction.kt.193
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2010-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 org.jetbrains.kotlin.idea.actions
+
+import com.intellij.openapi.actionSystem.AnAction
+import com.intellij.openapi.actionSystem.AnActionEvent
+import com.intellij.openapi.actionSystem.CommonDataKeys
+import com.intellij.openapi.wm.ToolWindowAnchor
+import com.intellij.openapi.wm.ToolWindowManager
+import com.intellij.ui.content.ContentFactory
+import org.jetbrains.kotlin.idea.KotlinFileType
+import org.jetbrains.kotlin.idea.KotlinIcons
+import org.jetbrains.kotlin.idea.internal.KotlinBytecodeToolWindow
+
+class ShowKotlinBytecodeAction : AnAction() {
+ val TOOLWINDOW_ID = "Kotlin Bytecode"
+
+ override fun actionPerformed(e: AnActionEvent) {
+ val project = e.project ?: return
+ val toolWindowManager = ToolWindowManager.getInstance(project)
+
+ var toolWindow = toolWindowManager.getToolWindow(TOOLWINDOW_ID)
+ if (toolWindow == null) {
+ toolWindow = toolWindowManager.registerToolWindow("Kotlin Bytecode", false, ToolWindowAnchor.RIGHT)
+ toolWindow.icon = KotlinIcons.SMALL_LOGO_13
+
+ val contentManager = toolWindow.contentManager
+ val contentFactory = ContentFactory.SERVICE.getInstance()
+ contentManager.addContent(contentFactory.createContent(KotlinBytecodeToolWindow(project, toolWindow), "", false))
+ }
+ toolWindow.activate(null)
+ }
+
+ override fun update(e: AnActionEvent) {
+ val file = e.getData(CommonDataKeys.PSI_FILE)
+ e.presentation.isEnabled = e.project != null && file?.fileType == KotlinFileType.INSTANCE
+ }
+}
diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/output/ToolWindowScratchOutputHandler.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/output/ToolWindowScratchOutputHandler.kt
index 5c0dd47..a52c20c 100644
--- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/output/ToolWindowScratchOutputHandler.kt
+++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/output/ToolWindowScratchOutputHandler.kt
@@ -1,284 +1,274 @@
-/*
- * Copyright 2010-2017 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.jetbrains.kotlin.idea.scratch.output
-
-import com.intellij.execution.filters.OpenFileHyperlinkInfo
-import com.intellij.execution.impl.ConsoleViewImpl
-import com.intellij.execution.runners.ExecutionUtil
-import com.intellij.execution.ui.ConsoleViewContentType
-import com.intellij.openapi.Disposable
-import com.intellij.openapi.application.ApplicationManager
-import com.intellij.openapi.application.TransactionGuard
-import com.intellij.openapi.command.WriteCommandAction
-import com.intellij.openapi.editor.ex.EditorEx
-import com.intellij.openapi.fileTypes.PlainTextFileType
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.util.Disposer
-import com.intellij.openapi.wm.ToolWindow
-import com.intellij.openapi.wm.ToolWindowAnchor
-import com.intellij.openapi.wm.ToolWindowFactory
-import com.intellij.openapi.wm.ToolWindowManager
-import com.intellij.psi.PsiFile
-import org.jetbrains.kotlin.idea.scratch.ScratchExpression
-import org.jetbrains.kotlin.idea.scratch.ScratchFile
-import org.jetbrains.kotlin.psi.KtPsiFactory
-
-/**
- * Method to retrieve shared instance of scratches ToolWindow output handler.
- *
- * [releaseToolWindowHandler] must be called for every output handler received from this method.
- *
- * Can be called from EDT only.
- *
- * @return new toolWindow output handler if one does not exist, otherwise returns the existing one. When application in test mode,
- * returns [TestOutputHandler].
- */
-fun requestToolWindowHandler(): ScratchOutputHandler {
- return if (ApplicationManager.getApplication().isUnitTestMode) {
- TestOutputHandler
- } else {
- ScratchToolWindowHandlerKeeper.requestOutputHandler()
- }
-}
-
-/**
- * Should be called once with the output handler received from the [requestToolWindowHandler] call.
- *
- * When release is called for every request, the output handler is actually disposed.
- *
- * When application in test mode, does nothing.
- *
- * Can be called from EDT only.
- */
-fun releaseToolWindowHandler(scratchOutputHandler: ScratchOutputHandler) {
- if (!ApplicationManager.getApplication().isUnitTestMode) {
- ScratchToolWindowHandlerKeeper.releaseOutputHandler(scratchOutputHandler)
- }
-}
-
-/**
- * Implements logic of shared pointer for the toolWindow output handler.
- *
- * Not thread safe! Can be used only from the EDT.
- */
-private object ScratchToolWindowHandlerKeeper {
- private var toolWindowHandler: ScratchOutputHandler? = null
- private var toolWindowDisposable = Disposer.newDisposable()
- private var counter = 0
-
- fun requestOutputHandler(): ScratchOutputHandler {
- if (counter == 0) {
- toolWindowHandler = ToolWindowScratchOutputHandler(toolWindowDisposable)
- }
-
- counter += 1
- return toolWindowHandler!!
- }
-
- fun releaseOutputHandler(scratchOutputHandler: ScratchOutputHandler) {
- require(counter > 0) { "Counter is $counter, nothing to release!" }
- require(toolWindowHandler === scratchOutputHandler) { "$scratchOutputHandler differs from stored $toolWindowHandler" }
-
- counter -= 1
- if (counter == 0) {
- Disposer.dispose(toolWindowDisposable)
- toolWindowDisposable = Disposer.newDisposable()
- toolWindowHandler = null
- }
- }
-}
-
-private class ToolWindowScratchOutputHandler(private val parentDisposable: Disposable) : ScratchOutputHandlerAdapter() {
-
- override fun handle(file: ScratchFile, expression: ScratchExpression, output: ScratchOutput) {
- printToConsole(file) {
- val psiFile = file.getPsiFile()
- if (psiFile != null) {
- printHyperlink(
- getLineInfo(psiFile, expression),
- OpenFileHyperlinkInfo(
- project,
- psiFile.virtualFile,
- expression.lineStart,
- ),
- )
- print(" ", ConsoleViewContentType.NORMAL_OUTPUT)
- }
- print(output.text, output.type.convert())
- }
- }
-
- override fun error(file: ScratchFile, message: String) {
- printToConsole(file) {
- print(message, ConsoleViewContentType.ERROR_OUTPUT)
- }
- }
-
- private fun printToConsole(file: ScratchFile, print: ConsoleViewImpl.() -> Unit) {
- ApplicationManager.getApplication().invokeLater {
- val project = file.project.takeIf { !it.isDisposed } ?: return@invokeLater
-
- val toolWindow = getToolWindow(project) ?: createToolWindow(file)
-
- val contents = toolWindow.contentManager.contents
- for (content in contents) {
- val component = content.component
- if (component is ConsoleViewImpl) {
- component.print()
- component.print("\n", ConsoleViewContentType.NORMAL_OUTPUT)
- }
- }
-
- toolWindow.setAvailable(true, null)
-
- if (!file.options.isInteractiveMode) {
- toolWindow.show(null)
- }
-
- toolWindow.icon = ExecutionUtil.getLiveIndicator(scratchIcon())
- }
- }
-
- override fun clear(file: ScratchFile) {
- ApplicationManager.getApplication().invokeLater {
- val toolWindow = getToolWindow(file.project) ?: return@invokeLater
- val contents = toolWindow.contentManager.contents
- for (content in contents) {
- val component = content.component
- if (component is ConsoleViewImpl) {
- component.clear()
- }
- }
-
- if (!file.options.isInteractiveMode) {
- toolWindow.hide(null)
- }
-
- toolWindow.icon = scratchIcon()
- }
- }
-
- private fun ScratchOutputType.convert() = when (this) {
- ScratchOutputType.OUTPUT -> ConsoleViewContentType.SYSTEM_OUTPUT
- ScratchOutputType.RESULT -> ConsoleViewContentType.NORMAL_OUTPUT
- ScratchOutputType.ERROR -> ConsoleViewContentType.ERROR_OUTPUT
- }
-
- private fun getToolWindow(project: Project): ToolWindow? {
- val toolWindowManager = ToolWindowManager.getInstance(project)
- return toolWindowManager.getToolWindow(ScratchToolWindowFactory.ID)
- }
-
- private fun createToolWindow(file: ScratchFile): ToolWindow {
- val project = file.project
- val toolWindowManager = ToolWindowManager.getInstance(project)
- toolWindowManager.registerToolWindow(ScratchToolWindowFactory.ID, true, ToolWindowAnchor.BOTTOM)
- val window = toolWindowManager.getToolWindow(ScratchToolWindowFactory.ID)
- ScratchToolWindowFactory().createToolWindowContent(project, window)
-
- Disposer.register(
- parentDisposable,
- Disposable {
- toolWindowManager.unregisterToolWindow(ScratchToolWindowFactory.ID)
- },
- )
-
- return window
- }
-}
-
-private fun scratchIcon() = PlainTextFileType.INSTANCE.icon
-
-private fun getLineInfo(psiFile: PsiFile, expression: ScratchExpression) =
- "${psiFile.name}:${expression.lineStart + 1}"
-
-private class ScratchToolWindowFactory : ToolWindowFactory {
- companion object {
- const val ID = "Scratch Output"
- }
-
- override fun createToolWindowContent(project: Project, toolWindow: ToolWindow) {
- val consoleView = ConsoleViewImpl(project, true)
- toolWindow.isToHideOnEmptyContent = true
- toolWindow.icon = scratchIcon()
- toolWindow.hide(null)
-
- val contentManager = toolWindow.contentManager
- val content = contentManager.factory.createContent(consoleView.component, null, false)
- contentManager.addContent(content)
- val editor = consoleView.editor
- if (editor is EditorEx) {
- editor.isRendererMode = true
- }
-
- Disposer.register(project, consoleView)
- }
-}
-
-private object TestOutputHandler : ScratchOutputHandlerAdapter() {
- private val errors = arrayListOf<String>()
- private val inlays = arrayListOf<Pair<ScratchExpression, String>>()
-
- override fun handle(file: ScratchFile, expression: ScratchExpression, output: ScratchOutput) {
- inlays.add(expression to output.text)
- }
-
- override fun error(file: ScratchFile, message: String) {
- errors.add(message)
- }
-
- override fun onFinish(file: ScratchFile) {
- TransactionGuard.submitTransaction(
- file.project,
- Runnable {
- val psiFile = file.getPsiFile()
- ?: error(
- "PsiFile cannot be found for scratch to render inlays in tests:\n" +
- "project.isDisposed = ${file.project.isDisposed}\n" +
- "inlays = ${inlays.joinToString { it.second }}\n" +
- "errors = ${errors.joinToString()}",
- )
-
- if (inlays.isNotEmpty()) {
- testPrint(
- psiFile,
- inlays.map { (expression, text) ->
- "/** ${getLineInfo(psiFile, expression)} $text */"
- },
- )
- inlays.clear()
- }
-
- if (errors.isNotEmpty()) {
- testPrint(psiFile, listOf(errors.joinToString(prefix = "/** ", postfix = " */")))
- errors.clear()
- }
- },
- )
- }
-
- private fun testPrint(file: PsiFile, comments: List<String>) {
- WriteCommandAction.runWriteCommandAction(file.project) {
- for (comment in comments) {
- file.addAfter(
- KtPsiFactory(file.project).createComment(comment),
- file.lastChild,
- )
- }
- }
- }
-}
+/*
+ * Copyright 2010-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlin.idea.scratch.output
+
+import com.intellij.execution.filters.OpenFileHyperlinkInfo
+import com.intellij.execution.impl.ConsoleViewImpl
+import com.intellij.execution.runners.ExecutionUtil
+import com.intellij.execution.ui.ConsoleViewContentType
+import com.intellij.ide.scratch.ScratchFileType
+import com.intellij.openapi.Disposable
+import com.intellij.openapi.application.ApplicationManager
+import com.intellij.openapi.application.TransactionGuard
+import com.intellij.openapi.command.WriteCommandAction
+import com.intellij.openapi.editor.ex.EditorEx
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.util.Disposer
+import com.intellij.openapi.wm.ToolWindow
+import com.intellij.openapi.wm.ToolWindowAnchor
+import com.intellij.openapi.wm.ToolWindowFactory
+import com.intellij.openapi.wm.ToolWindowManager
+import com.intellij.psi.PsiFile
+import org.jetbrains.kotlin.idea.scratch.ScratchExpression
+import org.jetbrains.kotlin.idea.scratch.ScratchFile
+import org.jetbrains.kotlin.psi.KtPsiFactory
+
+/**
+ * Method to retrieve shared instance of scratches ToolWindow output handler.
+ *
+ * [releaseToolWindowHandler] must be called for every output handler received from this method.
+ *
+ * Can be called from EDT only.
+ *
+ * @return new toolWindow output handler if one does not exist, otherwise returns the existing one. When application in test mode,
+ * returns [TestOutputHandler].
+ */
+fun requestToolWindowHandler(): ScratchOutputHandler {
+ return if (ApplicationManager.getApplication().isUnitTestMode) {
+ TestOutputHandler
+ } else {
+ ScratchToolWindowHandlerKeeper.requestOutputHandler()
+ }
+}
+
+/**
+ * Should be called once with the output handler received from the [requestToolWindowHandler] call.
+ *
+ * When release is called for every request, the output handler is actually disposed.
+ *
+ * When application in test mode, does nothing.
+ *
+ * Can be called from EDT only.
+ */
+fun releaseToolWindowHandler(scratchOutputHandler: ScratchOutputHandler) {
+ if (!ApplicationManager.getApplication().isUnitTestMode) {
+ ScratchToolWindowHandlerKeeper.releaseOutputHandler(scratchOutputHandler)
+ }
+}
+
+/**
+ * Implements logic of shared pointer for the toolWindow output handler.
+ *
+ * Not thread safe! Can be used only from the EDT.
+ */
+private object ScratchToolWindowHandlerKeeper {
+ private var toolWindowHandler: ScratchOutputHandler? = null
+ private var toolWindowDisposable = Disposer.newDisposable()
+ private var counter = 0
+
+ fun requestOutputHandler(): ScratchOutputHandler {
+ if (counter == 0) {
+ toolWindowHandler = ToolWindowScratchOutputHandler(toolWindowDisposable)
+ }
+
+ counter += 1
+ return toolWindowHandler!!
+ }
+
+ fun releaseOutputHandler(scratchOutputHandler: ScratchOutputHandler) {
+ require(counter > 0) { "Counter is $counter, nothing to release!" }
+ require(toolWindowHandler === scratchOutputHandler) { "$scratchOutputHandler differs from stored $toolWindowHandler" }
+
+ counter -= 1
+ if (counter == 0) {
+ Disposer.dispose(toolWindowDisposable)
+ toolWindowDisposable = Disposer.newDisposable()
+ toolWindowHandler = null
+ }
+ }
+}
+
+private class ToolWindowScratchOutputHandler(private val parentDisposable: Disposable) : ScratchOutputHandlerAdapter() {
+
+ override fun handle(file: ScratchFile, expression: ScratchExpression, output: ScratchOutput) {
+ printToConsole(file) {
+ val psiFile = file.getPsiFile()
+ if (psiFile != null) {
+ printHyperlink(
+ getLineInfo(psiFile, expression),
+ OpenFileHyperlinkInfo(
+ project,
+ psiFile.virtualFile,
+ expression.lineStart
+ )
+ )
+ print(" ", ConsoleViewContentType.NORMAL_OUTPUT)
+ }
+ print(output.text, output.type.convert())
+ }
+ }
+
+ override fun error(file: ScratchFile, message: String) {
+ printToConsole(file) {
+ print(message, ConsoleViewContentType.ERROR_OUTPUT)
+ }
+ }
+
+ private fun printToConsole(file: ScratchFile, print: ConsoleViewImpl.() -> Unit) {
+ ApplicationManager.getApplication().invokeLater {
+ val project = file.project.takeIf { !it.isDisposed } ?: return@invokeLater
+
+ val toolWindow = getToolWindow(project) ?: createToolWindow(file)
+
+ val contents = toolWindow.contentManager.contents
+ for (content in contents) {
+ val component = content.component
+ if (component is ConsoleViewImpl) {
+ component.print()
+ component.print("\n", ConsoleViewContentType.NORMAL_OUTPUT)
+ }
+ }
+
+ toolWindow.setAvailable(true, null)
+
+ if (!file.options.isInteractiveMode) {
+ toolWindow.show(null)
+ }
+
+ toolWindow.setIcon(ExecutionUtil.getLiveIndicator(ScratchFileType.INSTANCE.icon))
+ }
+ }
+
+ override fun clear(file: ScratchFile) {
+ ApplicationManager.getApplication().invokeLater {
+ val toolWindow = getToolWindow(file.project) ?: return@invokeLater
+ val contents = toolWindow.contentManager.contents
+ for (content in contents) {
+ val component = content.component
+ if (component is ConsoleViewImpl) {
+ component.clear()
+ }
+ }
+
+ if (!file.options.isInteractiveMode) {
+ toolWindow.hide(null)
+ }
+
+ toolWindow.setIcon(ScratchFileType.INSTANCE.icon ?: error("Text icon is expected to be present"))
+ }
+ }
+
+ private fun ScratchOutputType.convert() = when (this) {
+ ScratchOutputType.OUTPUT -> ConsoleViewContentType.SYSTEM_OUTPUT
+ ScratchOutputType.RESULT -> ConsoleViewContentType.NORMAL_OUTPUT
+ ScratchOutputType.ERROR -> ConsoleViewContentType.ERROR_OUTPUT
+ }
+
+ private fun getToolWindow(project: Project): ToolWindow? {
+ val toolWindowManager = ToolWindowManager.getInstance(project)
+ return toolWindowManager.getToolWindow(ScratchToolWindowFactory.ID)
+ }
+
+ private fun createToolWindow(file: ScratchFile): ToolWindow {
+ val project = file.project
+ val toolWindowManager = ToolWindowManager.getInstance(project)
+ toolWindowManager.registerToolWindow(ScratchToolWindowFactory.ID, true, ToolWindowAnchor.BOTTOM)
+ val window =
+ toolWindowManager.getToolWindow(ScratchToolWindowFactory.ID) ?: error("ScratchToolWindowFactory.ID should be registered")
+ ScratchToolWindowFactory().createToolWindowContent(project, window)
+
+ Disposer.register(parentDisposable, Disposable {
+ toolWindowManager.unregisterToolWindow(ScratchToolWindowFactory.ID)
+ })
+
+ return window
+ }
+}
+
+private fun getLineInfo(psiFile: PsiFile, expression: ScratchExpression) =
+ "${psiFile.name}:${expression.lineStart + 1}"
+
+private class ScratchToolWindowFactory : ToolWindowFactory {
+ companion object {
+ const val ID = "Scratch Output"
+ }
+
+ override fun createToolWindowContent(project: Project, toolWindow: ToolWindow) {
+ val consoleView = ConsoleViewImpl(project, true)
+ toolWindow.setToHideOnEmptyContent(true)
+ toolWindow.setIcon(ScratchFileType.INSTANCE.icon ?: error("Text icon should be present"))
+ toolWindow.hide(null)
+
+ val contentManager = toolWindow.contentManager
+ val content = contentManager.factory.createContent(consoleView.component, null, false)
+ contentManager.addContent(content)
+ val editor = consoleView.editor
+ if (editor is EditorEx) {
+ editor.isRendererMode = true
+ }
+
+ Disposer.register(project, consoleView)
+ }
+}
+
+private object TestOutputHandler : ScratchOutputHandlerAdapter() {
+ private val errors = arrayListOf<String>()
+ private val inlays = arrayListOf<Pair<ScratchExpression, String>>()
+
+ override fun handle(file: ScratchFile, expression: ScratchExpression, output: ScratchOutput) {
+ inlays.add(expression to output.text)
+ }
+
+ override fun error(file: ScratchFile, message: String) {
+ errors.add(message)
+ }
+
+ override fun onFinish(file: ScratchFile) {
+ TransactionGuard.submitTransaction(file.project, Runnable {
+ val psiFile = file.getPsiFile()
+ ?: error(
+ "PsiFile cannot be found for scratch to render inlays in tests:\n" +
+ "project.isDisposed = ${file.project.isDisposed}\n" +
+ "inlays = ${inlays.joinToString { it.second }}\n" +
+ "errors = ${errors.joinToString()}"
+ )
+
+ if (inlays.isNotEmpty()) {
+ testPrint(psiFile, inlays.map { (expression, text) ->
+ "/** ${getLineInfo(psiFile, expression)} $text */"
+ })
+ inlays.clear()
+ }
+
+ if (errors.isNotEmpty()) {
+ testPrint(psiFile, listOf(errors.joinToString(prefix = "/** ", postfix = " */")))
+ errors.clear()
+ }
+ })
+ }
+
+ private fun testPrint(file: PsiFile, comments: List<String>) {
+ WriteCommandAction.runWriteCommandAction(file.project) {
+ for (comment in comments) {
+ file.addAfter(
+ KtPsiFactory(file.project).createComment(comment),
+ file.lastChild
+ )
+ }
+ }
+ }
+}
diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/output/ToolWindowScratchOutputHandler.kt.193 b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/output/ToolWindowScratchOutputHandler.kt.193
new file mode 100644
index 0000000..55d1f81
--- /dev/null
+++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/output/ToolWindowScratchOutputHandler.kt.193
@@ -0,0 +1,284 @@
+/*
+ * Copyright 2010-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlin.idea.scratch.output
+
+import com.intellij.execution.filters.OpenFileHyperlinkInfo
+import com.intellij.execution.impl.ConsoleViewImpl
+import com.intellij.execution.runners.ExecutionUtil
+import com.intellij.execution.ui.ConsoleViewContentType
+import com.intellij.openapi.Disposable
+import com.intellij.openapi.application.ApplicationManager
+import com.intellij.openapi.application.TransactionGuard
+import com.intellij.openapi.command.WriteCommandAction
+import com.intellij.openapi.editor.ex.EditorEx
+import com.intellij.openapi.fileTypes.PlainTextFileType
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.util.Disposer
+import com.intellij.openapi.wm.ToolWindow
+import com.intellij.openapi.wm.ToolWindowAnchor
+import com.intellij.openapi.wm.ToolWindowFactory
+import com.intellij.openapi.wm.ToolWindowManager
+import com.intellij.psi.PsiFile
+import org.jetbrains.kotlin.idea.scratch.ScratchExpression
+import org.jetbrains.kotlin.idea.scratch.ScratchFile
+import org.jetbrains.kotlin.psi.KtPsiFactory
+
+/**
+ * Method to retrieve shared instance of scratches ToolWindow output handler.
+ *
+ * [releaseToolWindowHandler] must be called for every output handler received from this method.
+ *
+ * Can be called from EDT only.
+ *
+ * @return new toolWindow output handler if one does not exist, otherwise returns the existing one. When application in test mode,
+ * returns [TestOutputHandler].
+ */
+fun requestToolWindowHandler(): ScratchOutputHandler {
+ return if (ApplicationManager.getApplication().isUnitTestMode) {
+ TestOutputHandler
+ } else {
+ ScratchToolWindowHandlerKeeper.requestOutputHandler()
+ }
+}
+
+/**
+ * Should be called once with the output handler received from the [requestToolWindowHandler] call.
+ *
+ * When release is called for every request, the output handler is actually disposed.
+ *
+ * When application in test mode, does nothing.
+ *
+ * Can be called from EDT only.
+ */
+fun releaseToolWindowHandler(scratchOutputHandler: ScratchOutputHandler) {
+ if (!ApplicationManager.getApplication().isUnitTestMode) {
+ ScratchToolWindowHandlerKeeper.releaseOutputHandler(scratchOutputHandler)
+ }
+}
+
+/**
+ * Implements logic of shared pointer for the toolWindow output handler.
+ *
+ * Not thread safe! Can be used only from the EDT.
+ */
+private object ScratchToolWindowHandlerKeeper {
+ private var toolWindowHandler: ScratchOutputHandler? = null
+ private var toolWindowDisposable = Disposer.newDisposable()
+ private var counter = 0
+
+ fun requestOutputHandler(): ScratchOutputHandler {
+ if (counter == 0) {
+ toolWindowHandler = ToolWindowScratchOutputHandler(toolWindowDisposable)
+ }
+
+ counter += 1
+ return toolWindowHandler!!
+ }
+
+ fun releaseOutputHandler(scratchOutputHandler: ScratchOutputHandler) {
+ require(counter > 0) { "Counter is $counter, nothing to release!" }
+ require(toolWindowHandler === scratchOutputHandler) { "$scratchOutputHandler differs from stored $toolWindowHandler" }
+
+ counter -= 1
+ if (counter == 0) {
+ Disposer.dispose(toolWindowDisposable)
+ toolWindowDisposable = Disposer.newDisposable()
+ toolWindowHandler = null
+ }
+ }
+}
+
+private class ToolWindowScratchOutputHandler(private val parentDisposable: Disposable) : ScratchOutputHandlerAdapter() {
+
+ override fun handle(file: ScratchFile, expression: ScratchExpression, output: ScratchOutput) {
+ printToConsole(file) {
+ val psiFile = file.getPsiFile()
+ if (psiFile != null) {
+ printHyperlink(
+ getLineInfo(psiFile, expression),
+ OpenFileHyperlinkInfo(
+ project,
+ psiFile.virtualFile,
+ expression.lineStart,
+ ),
+ )
+ print(" ", ConsoleViewContentType.NORMAL_OUTPUT)
+ }
+ print(output.text, output.type.convert())
+ }
+ }
+
+ override fun error(file: ScratchFile, message: String) {
+ printToConsole(file) {
+ print(message, ConsoleViewContentType.ERROR_OUTPUT)
+ }
+ }
+
+ private fun printToConsole(file: ScratchFile, print: ConsoleViewImpl.() -> Unit) {
+ ApplicationManager.getApplication().invokeLater {
+ val project = file.project.takeIf { !it.isDisposed } ?: return@invokeLater
+
+ val toolWindow = getToolWindow(project) ?: createToolWindow(file)
+
+ val contents = toolWindow.contentManager.contents
+ for (content in contents) {
+ val component = content.component
+ if (component is ConsoleViewImpl) {
+ component.print()
+ component.print("\n", ConsoleViewContentType.NORMAL_OUTPUT)
+ }
+ }
+
+ toolWindow.setAvailable(true, null)
+
+ if (!file.options.isInteractiveMode) {
+ toolWindow.show(null)
+ }
+
+ toolWindow.icon = ExecutionUtil.getLiveIndicator(scratchIcon())
+ }
+ }
+
+ override fun clear(file: ScratchFile) {
+ ApplicationManager.getApplication().invokeLater {
+ val toolWindow = getToolWindow(file.project) ?: return@invokeLater
+ val contents = toolWindow.contentManager.contents
+ for (content in contents) {
+ val component = content.component
+ if (component is ConsoleViewImpl) {
+ component.clear()
+ }
+ }
+
+ if (!file.options.isInteractiveMode) {
+ toolWindow.hide(null)
+ }
+
+ toolWindow.icon = scratchIcon()
+ }
+ }
+
+ private fun ScratchOutputType.convert() = when (this) {
+ ScratchOutputType.OUTPUT -> ConsoleViewContentType.SYSTEM_OUTPUT
+ ScratchOutputType.RESULT -> ConsoleViewContentType.NORMAL_OUTPUT
+ ScratchOutputType.ERROR -> ConsoleViewContentType.ERROR_OUTPUT
+ }
+
+ private fun getToolWindow(project: Project): ToolWindow? {
+ val toolWindowManager = ToolWindowManager.getInstance(project)
+ return toolWindowManager.getToolWindow(ScratchToolWindowFactory.ID)
+ }
+
+ private fun createToolWindow(file: ScratchFile): ToolWindow {
+ val project = file.project
+ val toolWindowManager = ToolWindowManager.getInstance(project)
+ toolWindowManager.registerToolWindow(ScratchToolWindowFactory.ID, true, ToolWindowAnchor.BOTTOM)
+ val window = toolWindowManager.getToolWindow(ScratchToolWindowFactory.ID)
+ ScratchToolWindowFactory().createToolWindowContent(project, window)
+
+ Disposer.register(
+ parentDisposable,
+ Disposable {
+ toolWindowManager.unregisterToolWindow(ScratchToolWindowFactory.ID)
+ },
+ )
+
+ return window
+ }
+}
+
+private fun scratchIcon() = PlainTextFileType.INSTANCE.icon
+
+private fun getLineInfo(psiFile: PsiFile, expression: ScratchExpression) =
+ "${psiFile.name}:${expression.lineStart + 1}"
+
+private class ScratchToolWindowFactory : ToolWindowFactory {
+ companion object {
+ const val ID = "Scratch Output"
+ }
+
+ override fun createToolWindowContent(project: Project, toolWindow: ToolWindow) {
+ val consoleView = ConsoleViewImpl(project, true)
+ toolWindow.isToHideOnEmptyContent = true
+ toolWindow.icon = scratchIcon()
+ toolWindow.hide(null)
+
+ val contentManager = toolWindow.contentManager
+ val content = contentManager.factory.createContent(consoleView.component, null, false)
+ contentManager.addContent(content)
+ val editor = consoleView.editor
+ if (editor is EditorEx) {
+ editor.isRendererMode = true
+ }
+
+ Disposer.register(project, consoleView)
+ }
+}
+
+private object TestOutputHandler : ScratchOutputHandlerAdapter() {
+ private val errors = arrayListOf<String>()
+ private val inlays = arrayListOf<Pair<ScratchExpression, String>>()
+
+ override fun handle(file: ScratchFile, expression: ScratchExpression, output: ScratchOutput) {
+ inlays.add(expression to output.text)
+ }
+
+ override fun error(file: ScratchFile, message: String) {
+ errors.add(message)
+ }
+
+ override fun onFinish(file: ScratchFile) {
+ TransactionGuard.submitTransaction(
+ file.project,
+ Runnable {
+ val psiFile = file.getPsiFile()
+ ?: error(
+ "PsiFile cannot be found for scratch to render inlays in tests:\n" +
+ "project.isDisposed = ${file.project.isDisposed}\n" +
+ "inlays = ${inlays.joinToString { it.second }}\n" +
+ "errors = ${errors.joinToString()}",
+ )
+
+ if (inlays.isNotEmpty()) {
+ testPrint(
+ psiFile,
+ inlays.map { (expression, text) ->
+ "/** ${getLineInfo(psiFile, expression)} $text */"
+ },
+ )
+ inlays.clear()
+ }
+
+ if (errors.isNotEmpty()) {
+ testPrint(psiFile, listOf(errors.joinToString(prefix = "/** ", postfix = " */")))
+ errors.clear()
+ }
+ },
+ )
+ }
+
+ private fun testPrint(file: PsiFile, comments: List<String>) {
+ WriteCommandAction.runWriteCommandAction(file.project) {
+ for (comment in comments) {
+ file.addAfter(
+ KtPsiFactory(file.project).createComment(comment),
+ file.lastChild,
+ )
+ }
+ }
+ }
+}
diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ui/TextEditorWithPreview.java b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ui/TextEditorWithPreview.java
index 0b606cd..1d42dd8 100644
--- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ui/TextEditorWithPreview.java
+++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ui/TextEditorWithPreview.java
@@ -1,486 +1,483 @@
-/*
- * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
- * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
- */
-
-package org.jetbrains.kotlin.idea.scratch.ui;
-
-
-import com.intellij.codeHighlighting.BackgroundEditorHighlighter;
-import com.intellij.icons.AllIcons;
-import com.intellij.ide.structureView.StructureViewBuilder;
-import com.intellij.ide.util.PropertiesComponent;
-import com.intellij.openapi.Disposable;
-import com.intellij.openapi.actionSystem.*;
-import com.intellij.openapi.editor.ex.EditorGutterComponentEx;
-import com.intellij.openapi.fileEditor.*;
-import com.intellij.openapi.project.DumbAware;
-import com.intellij.openapi.util.Disposer;
-import com.intellij.openapi.util.Pair;
-import com.intellij.openapi.util.UserDataHolderBase;
-import com.intellij.openapi.wm.IdeFocusManager;
-import com.intellij.ui.JBSplitter;
-import com.intellij.util.ui.JBUI;
-import com.intellij.util.ui.UIUtil;
-import org.jetbrains.annotations.ApiStatus;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import javax.swing.*;
-import java.awt.*;
-import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Two panel editor with three states: Editor, Preview and Editor with Preview.
- * Based on SplitFileEditor by Valentin Fondaratov
- * <p/>
- * <b>NOTE:</b> This class is a copy of {@link com.intellij.openapi.fileEditor.TextEditorWithPreview} from the most recent intellij-community
- * repository. We cannot use bundled version of this class because it doesn't yet have customization methods
- * (namely {@link TextEditorWithPreview#createLeftToolbarActionGroup()}).
- * <p/>
- * {@link SplitEditorToolbar} is also copied from the platform.
- * <p/>
- * This class also may have some minimal customizations to allow tracking when its layout have been changed. In the future we hope to
- * remove this copied class entirely and to use the bundled version.
- */
-public class TextEditorWithPreview extends UserDataHolderBase implements FileEditor {
- protected final TextEditor myEditor;
- protected final FileEditor myPreview;
- @NotNull
- private final MyListenersMultimap myListenersGenerator = new MyListenersMultimap();
- private Layout myLayout;
- private JComponent myComponent;
- private SplitEditorToolbar myToolbarWrapper;
- private final String myName;
-
- public TextEditorWithPreview(@NotNull TextEditor editor, @NotNull FileEditor preview, @NotNull String editorName) {
- myEditor = editor;
- myPreview = preview;
- myName = editorName;
- }
-
- public TextEditorWithPreview(@NotNull TextEditor editor, @NotNull FileEditor preview) {
- this(editor, preview, "TextEditorWithPreview");
- }
-
- @Nullable
- @Override
- public BackgroundEditorHighlighter getBackgroundHighlighter() {
- return myEditor.getBackgroundHighlighter();
- }
-
- @Nullable
- @Override
- public FileEditorLocation getCurrentLocation() {
- return myEditor.getCurrentLocation();
- }
-
- @Nullable
- @Override
- public StructureViewBuilder getStructureViewBuilder() {
- return myEditor.getStructureViewBuilder();
- }
-
- @Override
- public void dispose() {
- Disposer.dispose(myEditor);
- Disposer.dispose(myPreview);
- }
-
- @Override
- public void selectNotify() {
- myEditor.selectNotify();
- myPreview.selectNotify();
- }
-
- @Override
- public void deselectNotify() {
- myEditor.deselectNotify();
- myPreview.deselectNotify();
- }
-
- @NotNull
- @Override
- public JComponent getComponent() {
- if (myComponent == null) {
- final JBSplitter splitter = new JBSplitter(false, 0.5f, 0.15f, 0.85f);
- splitter.setSplitterProportionKey(getSplitterProportionKey());
- splitter.setFirstComponent(myEditor.getComponent());
- splitter.setSecondComponent(myPreview.getComponent());
- splitter.setDividerWidth(3);
-
- myToolbarWrapper = createMarkdownToolbarWrapper(splitter);
- Disposer.register(this, myToolbarWrapper);
-
- if (myLayout == null) {
- String lastUsed = PropertiesComponent.getInstance().getValue(getLayoutPropertyName());
- setLayout(Layout.fromName(lastUsed, Layout.SHOW_EDITOR_AND_PREVIEW));
- }
- adjustEditorsVisibility();
-
- myComponent = JBUI.Panels.simplePanel(splitter).addToTop(myToolbarWrapper);
- }
- return myComponent;
- }
-
- @NotNull
- private SplitEditorToolbar createMarkdownToolbarWrapper (@NotNull JComponent targetComponentForActions) {
- final ActionToolbar leftToolbar = createToolbar();
- if (leftToolbar != null) {
- leftToolbar.setTargetComponent(targetComponentForActions);
- leftToolbar.setReservePlaceAutoPopupIcon(false);
- }
-
- final ActionToolbar rightToolbar = createRightToolbar();
- rightToolbar.setTargetComponent(targetComponentForActions);
- rightToolbar.setReservePlaceAutoPopupIcon(false);
-
- return new SplitEditorToolbar(leftToolbar, rightToolbar);
- }
-
- @Override
- public void setState(@NotNull FileEditorState state) {
- if (state instanceof MyFileEditorState) {
- final MyFileEditorState compositeState = (MyFileEditorState)state;
- if (compositeState.getFirstState() != null) {
- myEditor.setState(compositeState.getFirstState());
- }
- if (compositeState.getSecondState() != null) {
- myPreview.setState(compositeState.getSecondState());
- }
- if (compositeState.getSplitLayout() != null) {
- setLayout(compositeState.getSplitLayout());
- invalidateLayout();
- }
- }
- }
-
- private void adjustEditorsVisibility() {
- myEditor.getComponent().setVisible(myLayout == Layout.SHOW_EDITOR || myLayout == Layout.SHOW_EDITOR_AND_PREVIEW);
- myPreview.getComponent().setVisible(myLayout == Layout.SHOW_PREVIEW || myLayout == Layout.SHOW_EDITOR_AND_PREVIEW);
- }
-
- private void invalidateLayout() {
- adjustEditorsVisibility();
- myToolbarWrapper.refresh();
- myComponent.repaint();
-
- final JComponent focusComponent = getPreferredFocusedComponent();
- if (focusComponent != null) {
- IdeFocusManager.findInstanceByComponent(focusComponent).requestFocus(focusComponent, true);
- }
- }
-
- @NotNull
- protected String getSplitterProportionKey() {
- return "TextEditorWithPreview.SplitterProportionKey";
- }
-
- @Nullable
- @Override
- public JComponent getPreferredFocusedComponent() {
- switch (myLayout) {
- case SHOW_EDITOR_AND_PREVIEW:
- case SHOW_EDITOR:
- return myEditor.getPreferredFocusedComponent();
- case SHOW_PREVIEW:
- return myPreview.getPreferredFocusedComponent();
- default:
- throw new IllegalStateException(myLayout.myName);
- }
- }
-
- @NotNull
- @Override
- public String getName() {
- return myName;
- }
-
- @NotNull
- @Override
- public FileEditorState getState(@NotNull FileEditorStateLevel level) {
- return new MyFileEditorState(myLayout, myEditor.getState(level), myPreview.getState(level));
- }
-
- @Override
- public void addPropertyChangeListener(@NotNull PropertyChangeListener listener) {
- myEditor.addPropertyChangeListener(listener);
- myPreview.addPropertyChangeListener(listener);
-
- final DoublingEventListenerDelegate delegate = myListenersGenerator.addListenerAndGetDelegate(listener);
- myEditor.addPropertyChangeListener(delegate);
- myPreview.addPropertyChangeListener(delegate);
- }
-
- @Override
- public void removePropertyChangeListener(@NotNull PropertyChangeListener listener) {
- myEditor.removePropertyChangeListener(listener);
- myPreview.removePropertyChangeListener(listener);
-
- final DoublingEventListenerDelegate delegate = myListenersGenerator.removeListenerAndGetDelegate(listener);
- if (delegate != null) {
- myEditor.removePropertyChangeListener(delegate);
- myPreview.removePropertyChangeListener(delegate);
- }
- }
-
- @NotNull
- public TextEditor getTextEditor() {
- return myEditor;
- }
-
- public Layout getLayout() {
- return myLayout;
- }
-
- protected void setLayout(@NotNull Layout layout) {
- myLayout = layout;
- }
-
- static class MyFileEditorState implements FileEditorState {
- private final Layout mySplitLayout;
- private final FileEditorState myFirstState;
- private final FileEditorState mySecondState;
-
- MyFileEditorState(Layout layout, FileEditorState firstState, FileEditorState secondState) {
- mySplitLayout = layout;
- myFirstState = firstState;
- mySecondState = secondState;
- }
-
- @Nullable
- public Layout getSplitLayout() {
- return mySplitLayout;
- }
-
- @Nullable
- public FileEditorState getFirstState() {
- return myFirstState;
- }
-
- @Nullable
- public FileEditorState getSecondState() {
- return mySecondState;
- }
-
- @Override
- public boolean canBeMergedWith(FileEditorState otherState, FileEditorStateLevel level) {
- return otherState instanceof MyFileEditorState
- && (myFirstState == null || myFirstState.canBeMergedWith(((MyFileEditorState)otherState).myFirstState, level))
- && (mySecondState == null || mySecondState.canBeMergedWith(((MyFileEditorState)otherState).mySecondState, level));
- }
- }
-
- @Override
- public boolean isModified() {
- return myEditor.isModified() || myPreview.isModified();
- }
-
- @Override
- public boolean isValid() {
- return myEditor.isValid() && myPreview.isValid();
- }
-
- private class DoublingEventListenerDelegate implements PropertyChangeListener {
- @NotNull
- private final PropertyChangeListener myDelegate;
-
- private DoublingEventListenerDelegate(@NotNull PropertyChangeListener delegate) {
- myDelegate = delegate;
- }
-
- @Override
- public void propertyChange(PropertyChangeEvent evt) {
- myDelegate.propertyChange(
- new PropertyChangeEvent(TextEditorWithPreview.this, evt.getPropertyName(), evt.getOldValue(), evt.getNewValue()));
- }
- }
-
- private class MyListenersMultimap {
- private final Map<PropertyChangeListener, Pair<Integer, DoublingEventListenerDelegate>> myMap = new HashMap<>();
-
- @NotNull
- public DoublingEventListenerDelegate addListenerAndGetDelegate(@NotNull PropertyChangeListener listener) {
- if (!myMap.containsKey(listener)) {
- myMap.put(listener, Pair.create(1, new DoublingEventListenerDelegate(listener)));
- }
- else {
- final Pair<Integer, DoublingEventListenerDelegate> oldPair = myMap.get(listener);
- myMap.put(listener, Pair.create(oldPair.getFirst() + 1, oldPair.getSecond()));
- }
-
- return myMap.get(listener).getSecond();
- }
-
- @Nullable
- public DoublingEventListenerDelegate removeListenerAndGetDelegate(@NotNull PropertyChangeListener listener) {
- final Pair<Integer, DoublingEventListenerDelegate> oldPair = myMap.get(listener);
- if (oldPair == null) {
- return null;
- }
-
- if (oldPair.getFirst() == 1) {
- myMap.remove(listener);
- }
- else {
- myMap.put(listener, Pair.create(oldPair.getFirst() - 1, oldPair.getSecond()));
- }
- return oldPair.getSecond();
- }
- }
-
- @Nullable
- protected ActionToolbar createToolbar() {
- ActionGroup actionGroup = createLeftToolbarActionGroup();
- if (actionGroup != null) {
- return ActionManager.getInstance().createActionToolbar("TextEditorWithPreview", actionGroup, true);
- }
- else {
- return null;
- }
- }
-
- @Nullable
- protected ActionGroup createLeftToolbarActionGroup() {
- return null;
- }
-
- @NotNull
- private ActionToolbar createRightToolbar() {
- final ActionGroup viewActions = createViewActionGroup();
- final ActionGroup group = createRightToolbarActionGroup();
- final ActionGroup rightToolbarActions = group == null
- ? viewActions
- : new DefaultActionGroup(group, Separator.create(), viewActions);
- return ActionManager.getInstance().createActionToolbar("TextEditorWithPreview", rightToolbarActions, true);
- }
-
- @NotNull
- protected ActionGroup createViewActionGroup() {
- return new DefaultActionGroup(
- getShowEditorAction(),
- getShowEditorAndPreviewAction(),
- getShowPreviewAction()
- );
- }
-
- @Nullable
- protected ActionGroup createRightToolbarActionGroup() {
- return null;
- }
-
- @NotNull
- protected ToggleAction getShowEditorAction() {
- return new ChangeViewModeAction(Layout.SHOW_EDITOR);
- }
-
- @NotNull
- protected ToggleAction getShowPreviewAction() {
- return new ChangeViewModeAction(Layout.SHOW_PREVIEW);
- }
-
- @NotNull
- protected ToggleAction getShowEditorAndPreviewAction() {
- return new ChangeViewModeAction(Layout.SHOW_EDITOR_AND_PREVIEW);
- }
-
- public enum Layout {
- SHOW_EDITOR("Editor only", AllIcons.General.LayoutEditorOnly),
- SHOW_PREVIEW("Preview only", AllIcons.General.LayoutPreviewOnly),
- SHOW_EDITOR_AND_PREVIEW("Editor and Preview", AllIcons.General.LayoutEditorPreview);
-
- private final String myName;
- private final Icon myIcon;
-
- Layout(String name, Icon icon) {
- myName = name;
- myIcon = icon;
- }
-
- public static Layout fromName(String name, Layout defaultValue) {
- for (Layout layout : Layout.values()) {
- if (layout.myName.equals(name)) {
- return layout;
- }
- }
- return defaultValue;
- }
-
- public String getName() {
- return myName;
- }
-
- public Icon getIcon() {
- return myIcon;
- }
- }
-
- private class ChangeViewModeAction extends ToggleAction implements DumbAware {
- private final Layout myActionLayout;
-
- ChangeViewModeAction(Layout layout) {
- super(layout.getName(), layout.getName(), layout.getIcon());
- myActionLayout = layout;
- }
-
- @Override
- public boolean isSelected(@NotNull AnActionEvent e) {
- return myLayout == myActionLayout;
- }
-
- @Override
- public void setSelected(@NotNull AnActionEvent e, boolean state) {
- if (state) {
- setLayout(myActionLayout);
- PropertiesComponent.getInstance().setValue(getLayoutPropertyName(), myLayout.myName, Layout.SHOW_EDITOR_AND_PREVIEW.myName);
- adjustEditorsVisibility();
- }
- }
- }
-
- @NotNull
- private String getLayoutPropertyName() {
- return myName + "Layout";
- }
-}
-
-class SplitEditorToolbar extends JPanel implements Disposable {
-
- private final ActionToolbar myRightToolbar;
-
- public SplitEditorToolbar(@Nullable ActionToolbar leftToolbar, @NotNull ActionToolbar rightToolbar) {
- super(new GridBagLayout());
- myRightToolbar = rightToolbar;
-
- if (leftToolbar != null) {
- add(leftToolbar.getComponent());
- }
-
- final JPanel centerPanel = new JPanel(new BorderLayout());
- add(centerPanel, new GridBagConstraints(2, 0, 1, 1, 1.0, 1.0,
- GridBagConstraints.CENTER, GridBagConstraints.BOTH, JBUI.emptyInsets(), 0, 0));
-
- add(myRightToolbar.getComponent());
-
- setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, UIUtil.CONTRAST_BORDER_COLOR));
-
- if (leftToolbar != null) leftToolbar.updateActionsImmediately();
- rightToolbar.updateActionsImmediately();
- }
-
- @Deprecated
- @ApiStatus.ScheduledForRemoval
- public void addGutterToTrack(@NotNull EditorGutterComponentEx gutterComponentEx) {}
-
- public void refresh() {
- myRightToolbar.updateActionsImmediately();
- }
-
- @Deprecated
- @ApiStatus.ScheduledForRemoval
- @Override
- public void dispose() {}
+/*
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.scratch.ui;
+
+
+import com.intellij.codeHighlighting.BackgroundEditorHighlighter;
+import com.intellij.icons.AllIcons;
+import com.intellij.ide.structureView.StructureViewBuilder;
+import com.intellij.ide.util.PropertiesComponent;
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.actionSystem.*;
+import com.intellij.openapi.editor.ex.EditorGutterComponentEx;
+import com.intellij.openapi.fileEditor.*;
+import com.intellij.openapi.project.DumbAware;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.openapi.util.Pair;
+import com.intellij.openapi.util.UserDataHolderBase;
+import com.intellij.openapi.wm.IdeFocusManager;
+import com.intellij.ui.JBSplitter;
+import com.intellij.util.ui.JBUI;
+import com.intellij.util.ui.UIUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import java.awt.*;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Two panel editor with three states: Editor, Preview and Editor with Preview.
+ * Based on SplitFileEditor by Valentin Fondaratov
+ * <p/>
+ * <b>NOTE:</b> This class is a copy of {@link com.intellij.openapi.fileEditor.TextEditorWithPreview} from the most recent intellij-community
+ * repository. We cannot use bundled version of this class because it doesn't yet have customization methods
+ * (namely {@link TextEditorWithPreview#createLeftToolbarActionGroup()}).
+ * <p/>
+ * {@link SplitEditorToolbar} is also copied from the platform.
+ * <p/>
+ * This class also may have some minimal customizations to allow tracking when its layout have been changed. In the future we hope to
+ * remove this copied class entirely and to use the bundled version.
+ */
+public class TextEditorWithPreview extends UserDataHolderBase implements FileEditor {
+ protected final TextEditor myEditor;
+ protected final FileEditor myPreview;
+ @NotNull
+ private final MyListenersMultimap myListenersGenerator = new MyListenersMultimap();
+ private Layout myLayout;
+ private JComponent myComponent;
+ private SplitEditorToolbar myToolbarWrapper;
+ private final String myName;
+
+ public TextEditorWithPreview(@NotNull TextEditor editor, @NotNull FileEditor preview, @NotNull String editorName) {
+ myEditor = editor;
+ myPreview = preview;
+ myName = editorName;
+ }
+
+ public TextEditorWithPreview(@NotNull TextEditor editor, @NotNull FileEditor preview) {
+ this(editor, preview, "TextEditorWithPreview");
+ }
+
+ @Nullable
+ @Override
+ public BackgroundEditorHighlighter getBackgroundHighlighter() {
+ return myEditor.getBackgroundHighlighter();
+ }
+
+ @Nullable
+ @Override
+ public FileEditorLocation getCurrentLocation() {
+ return myEditor.getCurrentLocation();
+ }
+
+ @Nullable
+ @Override
+ public StructureViewBuilder getStructureViewBuilder() {
+ return myEditor.getStructureViewBuilder();
+ }
+
+ @Override
+ public void dispose() {
+ Disposer.dispose(myEditor);
+ Disposer.dispose(myPreview);
+ }
+
+ @Override
+ public void selectNotify() {
+ myEditor.selectNotify();
+ myPreview.selectNotify();
+ }
+
+ @Override
+ public void deselectNotify() {
+ myEditor.deselectNotify();
+ myPreview.deselectNotify();
+ }
+
+ @NotNull
+ @Override
+ public JComponent getComponent() {
+ if (myComponent == null) {
+ final JBSplitter splitter = new JBSplitter(false, 0.5f, 0.15f, 0.85f);
+ splitter.setSplitterProportionKey(getSplitterProportionKey());
+ splitter.setFirstComponent(myEditor.getComponent());
+ splitter.setSecondComponent(myPreview.getComponent());
+ splitter.setDividerWidth(3);
+
+ myToolbarWrapper = createMarkdownToolbarWrapper(splitter);
+ Disposer.register(this, myToolbarWrapper);
+
+ if (myLayout == null) {
+ String lastUsed = PropertiesComponent.getInstance().getValue(getLayoutPropertyName());
+ setLayout(Layout.fromName(lastUsed, Layout.SHOW_EDITOR_AND_PREVIEW));
+ }
+ adjustEditorsVisibility();
+
+ myComponent = JBUI.Panels.simplePanel(splitter).addToTop(myToolbarWrapper);
+ }
+ return myComponent;
+ }
+
+ @NotNull
+ private SplitEditorToolbar createMarkdownToolbarWrapper (@NotNull JComponent targetComponentForActions) {
+ final ActionToolbar leftToolbar = createToolbar();
+ if (leftToolbar != null) {
+ leftToolbar.setTargetComponent(targetComponentForActions);
+ leftToolbar.setReservePlaceAutoPopupIcon(false);
+ }
+
+ final ActionToolbar rightToolbar = createRightToolbar();
+ rightToolbar.setTargetComponent(targetComponentForActions);
+ rightToolbar.setReservePlaceAutoPopupIcon(false);
+
+ return new SplitEditorToolbar(leftToolbar, rightToolbar);
+ }
+
+ @Override
+ public void setState(@NotNull FileEditorState state) {
+ if (state instanceof MyFileEditorState) {
+ final MyFileEditorState compositeState = (MyFileEditorState)state;
+ if (compositeState.getFirstState() != null) {
+ myEditor.setState(compositeState.getFirstState());
+ }
+ if (compositeState.getSecondState() != null) {
+ myPreview.setState(compositeState.getSecondState());
+ }
+ if (compositeState.getSplitLayout() != null) {
+ setLayout(compositeState.getSplitLayout());
+ invalidateLayout();
+ }
+ }
+ }
+
+ private void adjustEditorsVisibility() {
+ myEditor.getComponent().setVisible(myLayout == Layout.SHOW_EDITOR || myLayout == Layout.SHOW_EDITOR_AND_PREVIEW);
+ myPreview.getComponent().setVisible(myLayout == Layout.SHOW_PREVIEW || myLayout == Layout.SHOW_EDITOR_AND_PREVIEW);
+ }
+
+ private void invalidateLayout() {
+ adjustEditorsVisibility();
+ myToolbarWrapper.refresh();
+ myComponent.repaint();
+
+ final JComponent focusComponent = getPreferredFocusedComponent();
+ if (focusComponent != null) {
+ IdeFocusManager.findInstanceByComponent(focusComponent).requestFocus(focusComponent, true);
+ }
+ }
+
+ @NotNull
+ protected String getSplitterProportionKey() {
+ return "TextEditorWithPreview.SplitterProportionKey";
+ }
+
+ @Nullable
+ @Override
+ public JComponent getPreferredFocusedComponent() {
+ switch (myLayout) {
+ case SHOW_EDITOR_AND_PREVIEW:
+ case SHOW_EDITOR:
+ return myEditor.getPreferredFocusedComponent();
+ case SHOW_PREVIEW:
+ return myPreview.getPreferredFocusedComponent();
+ default:
+ throw new IllegalStateException(myLayout.myName);
+ }
+ }
+
+ @NotNull
+ @Override
+ public String getName() {
+ return myName;
+ }
+
+ @NotNull
+ @Override
+ public FileEditorState getState(@NotNull FileEditorStateLevel level) {
+ return new MyFileEditorState(myLayout, myEditor.getState(level), myPreview.getState(level));
+ }
+
+ @Override
+ public void addPropertyChangeListener(@NotNull PropertyChangeListener listener) {
+ myEditor.addPropertyChangeListener(listener);
+ myPreview.addPropertyChangeListener(listener);
+
+ final DoublingEventListenerDelegate delegate = myListenersGenerator.addListenerAndGetDelegate(listener);
+ myEditor.addPropertyChangeListener(delegate);
+ myPreview.addPropertyChangeListener(delegate);
+ }
+
+ @Override
+ public void removePropertyChangeListener(@NotNull PropertyChangeListener listener) {
+ myEditor.removePropertyChangeListener(listener);
+ myPreview.removePropertyChangeListener(listener);
+
+ final DoublingEventListenerDelegate delegate = myListenersGenerator.removeListenerAndGetDelegate(listener);
+ if (delegate != null) {
+ myEditor.removePropertyChangeListener(delegate);
+ myPreview.removePropertyChangeListener(delegate);
+ }
+ }
+
+ @NotNull
+ public TextEditor getTextEditor() {
+ return myEditor;
+ }
+
+ public Layout getLayout() {
+ return myLayout;
+ }
+
+ protected void setLayout(@NotNull Layout layout) {
+ myLayout = layout;
+ }
+
+ static class MyFileEditorState implements FileEditorState {
+ private final Layout mySplitLayout;
+ private final FileEditorState myFirstState;
+ private final FileEditorState mySecondState;
+
+ MyFileEditorState(Layout layout, FileEditorState firstState, FileEditorState secondState) {
+ mySplitLayout = layout;
+ myFirstState = firstState;
+ mySecondState = secondState;
+ }
+
+ @Nullable
+ public Layout getSplitLayout() {
+ return mySplitLayout;
+ }
+
+ @Nullable
+ public FileEditorState getFirstState() {
+ return myFirstState;
+ }
+
+ @Nullable
+ public FileEditorState getSecondState() {
+ return mySecondState;
+ }
+
+ @Override
+ public boolean canBeMergedWith(FileEditorState otherState, FileEditorStateLevel level) {
+ return otherState instanceof MyFileEditorState
+ && (myFirstState == null || myFirstState.canBeMergedWith(((MyFileEditorState)otherState).myFirstState, level))
+ && (mySecondState == null || mySecondState.canBeMergedWith(((MyFileEditorState)otherState).mySecondState, level));
+ }
+ }
+
+ @Override
+ public boolean isModified() {
+ return myEditor.isModified() || myPreview.isModified();
+ }
+
+ @Override
+ public boolean isValid() {
+ return myEditor.isValid() && myPreview.isValid();
+ }
+
+ private class DoublingEventListenerDelegate implements PropertyChangeListener {
+ @NotNull
+ private final PropertyChangeListener myDelegate;
+
+ private DoublingEventListenerDelegate(@NotNull PropertyChangeListener delegate) {
+ myDelegate = delegate;
+ }
+
+ @Override
+ public void propertyChange(PropertyChangeEvent evt) {
+ myDelegate.propertyChange(
+ new PropertyChangeEvent(TextEditorWithPreview.this, evt.getPropertyName(), evt.getOldValue(), evt.getNewValue()));
+ }
+ }
+
+ private class MyListenersMultimap {
+ private final Map<PropertyChangeListener, Pair<Integer, DoublingEventListenerDelegate>> myMap = new HashMap<>();
+
+ @NotNull
+ public DoublingEventListenerDelegate addListenerAndGetDelegate(@NotNull PropertyChangeListener listener) {
+ if (!myMap.containsKey(listener)) {
+ myMap.put(listener, Pair.create(1, new DoublingEventListenerDelegate(listener)));
+ }
+ else {
+ final Pair<Integer, DoublingEventListenerDelegate> oldPair = myMap.get(listener);
+ myMap.put(listener, Pair.create(oldPair.getFirst() + 1, oldPair.getSecond()));
+ }
+
+ return myMap.get(listener).getSecond();
+ }
+
+ @Nullable
+ public DoublingEventListenerDelegate removeListenerAndGetDelegate(@NotNull PropertyChangeListener listener) {
+ final Pair<Integer, DoublingEventListenerDelegate> oldPair = myMap.get(listener);
+ if (oldPair == null) {
+ return null;
+ }
+
+ if (oldPair.getFirst() == 1) {
+ myMap.remove(listener);
+ }
+ else {
+ myMap.put(listener, Pair.create(oldPair.getFirst() - 1, oldPair.getSecond()));
+ }
+ return oldPair.getSecond();
+ }
+ }
+
+ @Nullable
+ protected ActionToolbar createToolbar() {
+ ActionGroup actionGroup = createLeftToolbarActionGroup();
+ if (actionGroup != null) {
+ return ActionManager.getInstance().createActionToolbar("TextEditorWithPreview", actionGroup, true);
+ }
+ else {
+ return null;
+ }
+ }
+
+ @Nullable
+ protected ActionGroup createLeftToolbarActionGroup() {
+ return null;
+ }
+
+ @NotNull
+ private ActionToolbar createRightToolbar() {
+ final ActionGroup viewActions = createViewActionGroup();
+ final ActionGroup group = createRightToolbarActionGroup();
+ final ActionGroup rightToolbarActions = group == null
+ ? viewActions
+ : new DefaultActionGroup(group, Separator.create(), viewActions);
+ return ActionManager.getInstance().createActionToolbar("TextEditorWithPreview", rightToolbarActions, true);
+ }
+
+ @NotNull
+ protected ActionGroup createViewActionGroup() {
+ return new DefaultActionGroup(
+ getShowEditorAction(),
+ getShowEditorAndPreviewAction(),
+ getShowPreviewAction()
+ );
+ }
+
+ @Nullable
+ protected ActionGroup createRightToolbarActionGroup() {
+ return null;
+ }
+
+ @NotNull
+ protected ToggleAction getShowEditorAction() {
+ return new ChangeViewModeAction(Layout.SHOW_EDITOR);
+ }
+
+ @NotNull
+ protected ToggleAction getShowPreviewAction() {
+ return new ChangeViewModeAction(Layout.SHOW_PREVIEW);
+ }
+
+ @NotNull
+ protected ToggleAction getShowEditorAndPreviewAction() {
+ return new ChangeViewModeAction(Layout.SHOW_EDITOR_AND_PREVIEW);
+ }
+
+ public enum Layout {
+ SHOW_EDITOR("Editor only", AllIcons.General.LayoutEditorOnly),
+ SHOW_PREVIEW("Preview only", AllIcons.General.LayoutPreviewOnly),
+ SHOW_EDITOR_AND_PREVIEW("Editor and Preview", AllIcons.General.LayoutEditorPreview);
+
+ private final String myName;
+ private final Icon myIcon;
+
+ Layout(String name, Icon icon) {
+ myName = name;
+ myIcon = icon;
+ }
+
+ public static Layout fromName(String name, Layout defaultValue) {
+ for (Layout layout : Layout.values()) {
+ if (layout.myName.equals(name)) {
+ return layout;
+ }
+ }
+ return defaultValue;
+ }
+
+ public String getName() {
+ return myName;
+ }
+
+ public Icon getIcon() {
+ return myIcon;
+ }
+ }
+
+ private class ChangeViewModeAction extends ToggleAction implements DumbAware {
+ private final Layout myActionLayout;
+
+ ChangeViewModeAction(Layout layout) {
+ super(layout.getName(), layout.getName(), layout.getIcon());
+ myActionLayout = layout;
+ }
+
+ @Override
+ public boolean isSelected(@NotNull AnActionEvent e) {
+ return myLayout == myActionLayout;
+ }
+
+ @Override
+ public void setSelected(@NotNull AnActionEvent e, boolean state) {
+ if (state) {
+ setLayout(myActionLayout);
+ PropertiesComponent.getInstance().setValue(getLayoutPropertyName(), myLayout.myName, Layout.SHOW_EDITOR_AND_PREVIEW.myName);
+ adjustEditorsVisibility();
+ }
+ }
+ }
+
+ @NotNull
+ private String getLayoutPropertyName() {
+ return myName + "Layout";
+ }
+}
+
+class SplitEditorToolbar extends JPanel implements Disposable {
+
+ private final ActionToolbar myRightToolbar;
+
+ public SplitEditorToolbar(@Nullable ActionToolbar leftToolbar, @NotNull ActionToolbar rightToolbar) {
+ super(new GridBagLayout());
+ myRightToolbar = rightToolbar;
+
+ if (leftToolbar != null) {
+ add(leftToolbar.getComponent());
+ }
+
+ final JPanel centerPanel = new JPanel(new BorderLayout());
+ add(centerPanel, new GridBagConstraints(2, 0, 1, 1, 1.0, 1.0,
+ GridBagConstraints.CENTER, GridBagConstraints.BOTH, JBUI.emptyInsets(), 0, 0));
+
+ add(myRightToolbar.getComponent());
+
+ setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, UIUtil.CONTRAST_BORDER_COLOR));
+
+ if (leftToolbar != null) leftToolbar.updateActionsImmediately();
+ rightToolbar.updateActionsImmediately();
+ }
+
+ @Deprecated
+ public void addGutterToTrack(@NotNull EditorGutterComponentEx gutterComponentEx) {}
+
+ public void refresh() {
+ myRightToolbar.updateActionsImmediately();
+ }
+
+ @Deprecated
+ @Override
+ public void dispose() {}
}
\ No newline at end of file
diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ui/TextEditorWithPreview.java.193 b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ui/TextEditorWithPreview.java.193
new file mode 100644
index 0000000..a7fadcd
--- /dev/null
+++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/ui/TextEditorWithPreview.java.193
@@ -0,0 +1,486 @@
+/*
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.scratch.ui;
+
+
+import com.intellij.codeHighlighting.BackgroundEditorHighlighter;
+import com.intellij.icons.AllIcons;
+import com.intellij.ide.structureView.StructureViewBuilder;
+import com.intellij.ide.util.PropertiesComponent;
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.actionSystem.*;
+import com.intellij.openapi.editor.ex.EditorGutterComponentEx;
+import com.intellij.openapi.fileEditor.*;
+import com.intellij.openapi.project.DumbAware;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.openapi.util.Pair;
+import com.intellij.openapi.util.UserDataHolderBase;
+import com.intellij.openapi.wm.IdeFocusManager;
+import com.intellij.ui.JBSplitter;
+import com.intellij.util.ui.JBUI;
+import com.intellij.util.ui.UIUtil;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import java.awt.*;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Two panel editor with three states: Editor, Preview and Editor with Preview.
+ * Based on SplitFileEditor by Valentin Fondaratov
+ * <p/>
+ * <b>NOTE:</b> This class is a copy of {@link com.intellij.openapi.fileEditor.TextEditorWithPreview} from the most recent intellij-community
+ * repository. We cannot use bundled version of this class because it doesn't yet have customization methods
+ * (namely {@link TextEditorWithPreview#createLeftToolbarActionGroup()}).
+ * <p/>
+ * {@link SplitEditorToolbar} is also copied from the platform.
+ * <p/>
+ * This class also may have some minimal customizations to allow tracking when its layout have been changed. In the future we hope to
+ * remove this copied class entirely and to use the bundled version.
+ */
+public class TextEditorWithPreview extends UserDataHolderBase implements FileEditor {
+ protected final TextEditor myEditor;
+ protected final FileEditor myPreview;
+ @NotNull
+ private final MyListenersMultimap myListenersGenerator = new MyListenersMultimap();
+ private Layout myLayout;
+ private JComponent myComponent;
+ private SplitEditorToolbar myToolbarWrapper;
+ private final String myName;
+
+ public TextEditorWithPreview(@NotNull TextEditor editor, @NotNull FileEditor preview, @NotNull String editorName) {
+ myEditor = editor;
+ myPreview = preview;
+ myName = editorName;
+ }
+
+ public TextEditorWithPreview(@NotNull TextEditor editor, @NotNull FileEditor preview) {
+ this(editor, preview, "TextEditorWithPreview");
+ }
+
+ @Nullable
+ @Override
+ public BackgroundEditorHighlighter getBackgroundHighlighter() {
+ return myEditor.getBackgroundHighlighter();
+ }
+
+ @Nullable
+ @Override
+ public FileEditorLocation getCurrentLocation() {
+ return myEditor.getCurrentLocation();
+ }
+
+ @Nullable
+ @Override
+ public StructureViewBuilder getStructureViewBuilder() {
+ return myEditor.getStructureViewBuilder();
+ }
+
+ @Override
+ public void dispose() {
+ Disposer.dispose(myEditor);
+ Disposer.dispose(myPreview);
+ }
+
+ @Override
+ public void selectNotify() {
+ myEditor.selectNotify();
+ myPreview.selectNotify();
+ }
+
+ @Override
+ public void deselectNotify() {
+ myEditor.deselectNotify();
+ myPreview.deselectNotify();
+ }
+
+ @NotNull
+ @Override
+ public JComponent getComponent() {
+ if (myComponent == null) {
+ final JBSplitter splitter = new JBSplitter(false, 0.5f, 0.15f, 0.85f);
+ splitter.setSplitterProportionKey(getSplitterProportionKey());
+ splitter.setFirstComponent(myEditor.getComponent());
+ splitter.setSecondComponent(myPreview.getComponent());
+ splitter.setDividerWidth(3);
+
+ myToolbarWrapper = createMarkdownToolbarWrapper(splitter);
+ Disposer.register(this, myToolbarWrapper);
+
+ if (myLayout == null) {
+ String lastUsed = PropertiesComponent.getInstance().getValue(getLayoutPropertyName());
+ setLayout(Layout.fromName(lastUsed, Layout.SHOW_EDITOR_AND_PREVIEW));
+ }
+ adjustEditorsVisibility();
+
+ myComponent = JBUI.Panels.simplePanel(splitter).addToTop(myToolbarWrapper);
+ }
+ return myComponent;
+ }
+
+ @NotNull
+ private SplitEditorToolbar createMarkdownToolbarWrapper (@NotNull JComponent targetComponentForActions) {
+ final ActionToolbar leftToolbar = createToolbar();
+ if (leftToolbar != null) {
+ leftToolbar.setTargetComponent(targetComponentForActions);
+ leftToolbar.setReservePlaceAutoPopupIcon(false);
+ }
+
+ final ActionToolbar rightToolbar = createRightToolbar();
+ rightToolbar.setTargetComponent(targetComponentForActions);
+ rightToolbar.setReservePlaceAutoPopupIcon(false);
+
+ return new SplitEditorToolbar(leftToolbar, rightToolbar);
+ }
+
+ @Override
+ public void setState(@NotNull FileEditorState state) {
+ if (state instanceof MyFileEditorState) {
+ final MyFileEditorState compositeState = (MyFileEditorState)state;
+ if (compositeState.getFirstState() != null) {
+ myEditor.setState(compositeState.getFirstState());
+ }
+ if (compositeState.getSecondState() != null) {
+ myPreview.setState(compositeState.getSecondState());
+ }
+ if (compositeState.getSplitLayout() != null) {
+ setLayout(compositeState.getSplitLayout());
+ invalidateLayout();
+ }
+ }
+ }
+
+ private void adjustEditorsVisibility() {
+ myEditor.getComponent().setVisible(myLayout == Layout.SHOW_EDITOR || myLayout == Layout.SHOW_EDITOR_AND_PREVIEW);
+ myPreview.getComponent().setVisible(myLayout == Layout.SHOW_PREVIEW || myLayout == Layout.SHOW_EDITOR_AND_PREVIEW);
+ }
+
+ private void invalidateLayout() {
+ adjustEditorsVisibility();
+ myToolbarWrapper.refresh();
+ myComponent.repaint();
+
+ final JComponent focusComponent = getPreferredFocusedComponent();
+ if (focusComponent != null) {
+ IdeFocusManager.findInstanceByComponent(focusComponent).requestFocus(focusComponent, true);
+ }
+ }
+
+ @NotNull
+ protected String getSplitterProportionKey() {
+ return "TextEditorWithPreview.SplitterProportionKey";
+ }
+
+ @Nullable
+ @Override
+ public JComponent getPreferredFocusedComponent() {
+ switch (myLayout) {
+ case SHOW_EDITOR_AND_PREVIEW:
+ case SHOW_EDITOR:
+ return myEditor.getPreferredFocusedComponent();
+ case SHOW_PREVIEW:
+ return myPreview.getPreferredFocusedComponent();
+ default:
+ throw new IllegalStateException(myLayout.myName);
+ }
+ }
+
+ @NotNull
+ @Override
+ public String getName() {
+ return myName;
+ }
+
+ @NotNull
+ @Override
+ public FileEditorState getState(@NotNull FileEditorStateLevel level) {
+ return new MyFileEditorState(myLayout, myEditor.getState(level), myPreview.getState(level));
+ }
+
+ @Override
+ public void addPropertyChangeListener(@NotNull PropertyChangeListener listener) {
+ myEditor.addPropertyChangeListener(listener);
+ myPreview.addPropertyChangeListener(listener);
+
+ final DoublingEventListenerDelegate delegate = myListenersGenerator.addListenerAndGetDelegate(listener);
+ myEditor.addPropertyChangeListener(delegate);
+ myPreview.addPropertyChangeListener(delegate);
+ }
+
+ @Override
+ public void removePropertyChangeListener(@NotNull PropertyChangeListener listener) {
+ myEditor.removePropertyChangeListener(listener);
+ myPreview.removePropertyChangeListener(listener);
+
+ final DoublingEventListenerDelegate delegate = myListenersGenerator.removeListenerAndGetDelegate(listener);
+ if (delegate != null) {
+ myEditor.removePropertyChangeListener(delegate);
+ myPreview.removePropertyChangeListener(delegate);
+ }
+ }
+
+ @NotNull
+ public TextEditor getTextEditor() {
+ return myEditor;
+ }
+
+ public Layout getLayout() {
+ return myLayout;
+ }
+
+ protected void setLayout(@NotNull Layout layout) {
+ myLayout = layout;
+ }
+
+ static class MyFileEditorState implements FileEditorState {
+ private final Layout mySplitLayout;
+ private final FileEditorState myFirstState;
+ private final FileEditorState mySecondState;
+
+ MyFileEditorState(Layout layout, FileEditorState firstState, FileEditorState secondState) {
+ mySplitLayout = layout;
+ myFirstState = firstState;
+ mySecondState = secondState;
+ }
+
+ @Nullable
+ public Layout getSplitLayout() {
+ return mySplitLayout;
+ }
+
+ @Nullable
+ public FileEditorState getFirstState() {
+ return myFirstState;
+ }
+
+ @Nullable
+ public FileEditorState getSecondState() {
+ return mySecondState;
+ }
+
+ @Override
+ public boolean canBeMergedWith(FileEditorState otherState, FileEditorStateLevel level) {
+ return otherState instanceof MyFileEditorState
+ && (myFirstState == null || myFirstState.canBeMergedWith(((MyFileEditorState)otherState).myFirstState, level))
+ && (mySecondState == null || mySecondState.canBeMergedWith(((MyFileEditorState)otherState).mySecondState, level));
+ }
+ }
+
+ @Override
+ public boolean isModified() {
+ return myEditor.isModified() || myPreview.isModified();
+ }
+
+ @Override
+ public boolean isValid() {
+ return myEditor.isValid() && myPreview.isValid();
+ }
+
+ private class DoublingEventListenerDelegate implements PropertyChangeListener {
+ @NotNull
+ private final PropertyChangeListener myDelegate;
+
+ private DoublingEventListenerDelegate(@NotNull PropertyChangeListener delegate) {
+ myDelegate = delegate;
+ }
+
+ @Override
+ public void propertyChange(PropertyChangeEvent evt) {
+ myDelegate.propertyChange(
+ new PropertyChangeEvent(TextEditorWithPreview.this, evt.getPropertyName(), evt.getOldValue(), evt.getNewValue()));
+ }
+ }
+
+ private class MyListenersMultimap {
+ private final Map<PropertyChangeListener, Pair<Integer, DoublingEventListenerDelegate>> myMap = new HashMap<>();
+
+ @NotNull
+ public DoublingEventListenerDelegate addListenerAndGetDelegate(@NotNull PropertyChangeListener listener) {
+ if (!myMap.containsKey(listener)) {
+ myMap.put(listener, Pair.create(1, new DoublingEventListenerDelegate(listener)));
+ }
+ else {
+ final Pair<Integer, DoublingEventListenerDelegate> oldPair = myMap.get(listener);
+ myMap.put(listener, Pair.create(oldPair.getFirst() + 1, oldPair.getSecond()));
+ }
+
+ return myMap.get(listener).getSecond();
+ }
+
+ @Nullable
+ public DoublingEventListenerDelegate removeListenerAndGetDelegate(@NotNull PropertyChangeListener listener) {
+ final Pair<Integer, DoublingEventListenerDelegate> oldPair = myMap.get(listener);
+ if (oldPair == null) {
+ return null;
+ }
+
+ if (oldPair.getFirst() == 1) {
+ myMap.remove(listener);
+ }
+ else {
+ myMap.put(listener, Pair.create(oldPair.getFirst() - 1, oldPair.getSecond()));
+ }
+ return oldPair.getSecond();
+ }
+ }
+
+ @Nullable
+ protected ActionToolbar createToolbar() {
+ ActionGroup actionGroup = createLeftToolbarActionGroup();
+ if (actionGroup != null) {
+ return ActionManager.getInstance().createActionToolbar("TextEditorWithPreview", actionGroup, true);
+ }
+ else {
+ return null;
+ }
+ }
+
+ @Nullable
+ protected ActionGroup createLeftToolbarActionGroup() {
+ return null;
+ }
+
+ @NotNull
+ private ActionToolbar createRightToolbar() {
+ final ActionGroup viewActions = createViewActionGroup();
+ final ActionGroup group = createRightToolbarActionGroup();
+ final ActionGroup rightToolbarActions = group == null
+ ? viewActions
+ : new DefaultActionGroup(group, Separator.create(), viewActions);
+ return ActionManager.getInstance().createActionToolbar("TextEditorWithPreview", rightToolbarActions, true);
+ }
+
+ @NotNull
+ protected ActionGroup createViewActionGroup() {
+ return new DefaultActionGroup(
+ getShowEditorAction(),
+ getShowEditorAndPreviewAction(),
+ getShowPreviewAction()
+ );
+ }
+
+ @Nullable
+ protected ActionGroup createRightToolbarActionGroup() {
+ return null;
+ }
+
+ @NotNull
+ protected ToggleAction getShowEditorAction() {
+ return new ChangeViewModeAction(Layout.SHOW_EDITOR);
+ }
+
+ @NotNull
+ protected ToggleAction getShowPreviewAction() {
+ return new ChangeViewModeAction(Layout.SHOW_PREVIEW);
+ }
+
+ @NotNull
+ protected ToggleAction getShowEditorAndPreviewAction() {
+ return new ChangeViewModeAction(Layout.SHOW_EDITOR_AND_PREVIEW);
+ }
+
+ public enum Layout {
+ SHOW_EDITOR("Editor only", AllIcons.General.LayoutEditorOnly),
+ SHOW_PREVIEW("Preview only", AllIcons.General.LayoutPreviewOnly),
+ SHOW_EDITOR_AND_PREVIEW("Editor and Preview", AllIcons.General.LayoutEditorPreview);
+
+ private final String myName;
+ private final Icon myIcon;
+
+ Layout(String name, Icon icon) {
+ myName = name;
+ myIcon = icon;
+ }
+
+ public static Layout fromName(String name, Layout defaultValue) {
+ for (Layout layout : Layout.values()) {
+ if (layout.myName.equals(name)) {
+ return layout;
+ }
+ }
+ return defaultValue;
+ }
+
+ public String getName() {
+ return myName;
+ }
+
+ public Icon getIcon() {
+ return myIcon;
+ }
+ }
+
+ private class ChangeViewModeAction extends ToggleAction implements DumbAware {
+ private final Layout myActionLayout;
+
+ ChangeViewModeAction(Layout layout) {
+ super(layout.getName(), layout.getName(), layout.getIcon());
+ myActionLayout = layout;
+ }
+
+ @Override
+ public boolean isSelected(@NotNull AnActionEvent e) {
+ return myLayout == myActionLayout;
+ }
+
+ @Override
+ public void setSelected(@NotNull AnActionEvent e, boolean state) {
+ if (state) {
+ setLayout(myActionLayout);
+ PropertiesComponent.getInstance().setValue(getLayoutPropertyName(), myLayout.myName, Layout.SHOW_EDITOR_AND_PREVIEW.myName);
+ adjustEditorsVisibility();
+ }
+ }
+ }
+
+ @NotNull
+ private String getLayoutPropertyName() {
+ return myName + "Layout";
+ }
+}
+
+class SplitEditorToolbar extends JPanel implements Disposable {
+
+ private final ActionToolbar myRightToolbar;
+
+ public SplitEditorToolbar(@Nullable ActionToolbar leftToolbar, @NotNull ActionToolbar rightToolbar) {
+ super(new GridBagLayout());
+ myRightToolbar = rightToolbar;
+
+ if (leftToolbar != null) {
+ add(leftToolbar.getComponent());
+ }
+
+ final JPanel centerPanel = new JPanel(new BorderLayout());
+ add(centerPanel, new GridBagConstraints(2, 0, 1, 1, 1.0, 1.0,
+ GridBagConstraints.CENTER, GridBagConstraints.BOTH, JBUI.emptyInsets(), 0, 0));
+
+ add(myRightToolbar.getComponent());
+
+ setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, UIUtil.CONTRAST_BORDER_COLOR));
+
+ if (leftToolbar != null) leftToolbar.updateActionsImmediately();
+ rightToolbar.updateActionsImmediately();
+ }
+
+ @Deprecated
+ @ApiStatus.ScheduledForRemoval
+ public void addGutterToTrack(@NotNull EditorGutterComponentEx gutterComponentEx) {}
+
+ public void refresh() {
+ myRightToolbar.updateActionsImmediately();
+ }
+
+ @Deprecated
+ @ApiStatus.ScheduledForRemoval
+ @Override
+ public void dispose() {}
+}
\ No newline at end of file
diff --git a/idea/idea-live-templates/tests/org/jetbrains/kotlin/idea/liveTemplates/compat.kt b/idea/idea-live-templates/tests/org/jetbrains/kotlin/idea/liveTemplates/compat.kt
index be64290..6971c2b 100644
--- a/idea/idea-live-templates/tests/org/jetbrains/kotlin/idea/liveTemplates/compat.kt
+++ b/idea/idea-live-templates/tests/org/jetbrains/kotlin/idea/liveTemplates/compat.kt
@@ -1,15 +1,15 @@
-/*
- * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
- * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
- */
-
-package org.jetbrains.kotlin.idea.liveTemplates
-
-import com.intellij.codeInsight.template.impl.TemplateManagerImpl
-import com.intellij.openapi.Disposable
-import com.intellij.openapi.project.Project
-
-// BUNCH: 193
-fun setTemplateTestingCompat(project: Project, disposable: Disposable) {
- TemplateManagerImpl.setTemplateTesting(project, disposable)
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.liveTemplates
+
+import com.intellij.codeInsight.template.impl.TemplateManagerImpl
+import com.intellij.openapi.Disposable
+import com.intellij.openapi.project.Project
+
+// BUNCH: 193
+fun setTemplateTestingCompat(project: Project, disposable: Disposable) {
+ TemplateManagerImpl.setTemplateTesting(disposable)
}
\ No newline at end of file
diff --git a/idea/idea-live-templates/tests/org/jetbrains/kotlin/idea/liveTemplates/compat.kt.193 b/idea/idea-live-templates/tests/org/jetbrains/kotlin/idea/liveTemplates/compat.kt.193
new file mode 100644
index 0000000..58fcec4
--- /dev/null
+++ b/idea/idea-live-templates/tests/org/jetbrains/kotlin/idea/liveTemplates/compat.kt.193
@@ -0,0 +1,15 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.liveTemplates
+
+import com.intellij.codeInsight.template.impl.TemplateManagerImpl
+import com.intellij.openapi.Disposable
+import com.intellij.openapi.project.Project
+
+// BUNCH: 193
+fun setTemplateTestingCompat(project: Project, disposable: Disposable) {
+ TemplateManagerImpl.setTemplateTesting(project, disposable)
+}
\ No newline at end of file
diff --git a/idea/idea-repl/src/org/jetbrains/kotlin/console/ConsoleCompilerHelper.kt b/idea/idea-repl/src/org/jetbrains/kotlin/console/ConsoleCompilerHelper.kt
index 296417b..bdcdf8d 100644
--- a/idea/idea-repl/src/org/jetbrains/kotlin/console/ConsoleCompilerHelper.kt
+++ b/idea/idea-repl/src/org/jetbrains/kotlin/console/ConsoleCompilerHelper.kt
@@ -1,52 +1,54 @@
-/*
- * Copyright 2010-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 org.jetbrains.kotlin.console
-
-import com.intellij.execution.ExecutionManager
-import com.intellij.execution.Executor
-import com.intellij.execution.ui.RunContentDescriptor
-import com.intellij.openapi.compiler.CompilerManager
-import com.intellij.openapi.module.Module
-import com.intellij.openapi.project.Project
-import com.intellij.task.ProjectTaskContext
-import com.intellij.task.ProjectTaskManager
-import com.intellij.task.ProjectTaskNotification
-import com.intellij.task.ProjectTaskResult
-
-class ConsoleCompilerHelper(
- private val project: Project,
- private val module: Module,
- private val executor: Executor,
- private val contentDescriptor: RunContentDescriptor
-) {
-
- fun moduleIsUpToDate(): Boolean {
- val compilerManager = CompilerManager.getInstance(project)
- val compilerScope = compilerManager.createModuleCompileScope(module, true)
- return compilerManager.isUpToDate(compilerScope)
- }
-
- fun compileModule() {
- if (ExecutionManager.getInstance(project).contentManager.removeRunContent(executor, contentDescriptor)) {
- ProjectTaskManager.getInstance(project).build(module).onSuccess { executionResult ->
- if (!module.isDisposed) {
- KotlinConsoleKeeper.getInstance(project).run(module, previousCompilationFailed = executionResult.hasErrors())
- }
- }
- }
- }
+/*
+ * Copyright 2010-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 org.jetbrains.kotlin.console
+
+import com.intellij.execution.ExecutionManager
+import com.intellij.execution.Executor
+import com.intellij.execution.ui.RunContentDescriptor
+import com.intellij.openapi.compiler.CompilerManager
+import com.intellij.openapi.module.Module
+import com.intellij.openapi.project.Project
+import com.intellij.task.ProjectTaskContext
+import com.intellij.task.ProjectTaskManager
+import com.intellij.task.ProjectTaskNotification
+import com.intellij.task.ProjectTaskResult
+
+class ConsoleCompilerHelper(
+ private val project: Project,
+ private val module: Module,
+ private val executor: Executor,
+ private val contentDescriptor: RunContentDescriptor
+) {
+
+ fun moduleIsUpToDate(): Boolean {
+ val compilerManager = CompilerManager.getInstance(project)
+ val compilerScope = compilerManager.createModuleCompileScope(module, true)
+ return compilerManager.isUpToDate(compilerScope)
+ }
+
+ fun compileModule() {
+ if (ExecutionManager.getInstance(project).getContentManager().removeRunContent(executor, contentDescriptor)) {
+ ProjectTaskManager.getInstance(project).build(arrayOf(module), object : ProjectTaskNotification {
+ override fun finished(context: ProjectTaskContext, executionResult: ProjectTaskResult) {
+ if (!module.isDisposed) {
+ KotlinConsoleKeeper.getInstance(project).run(module, previousCompilationFailed = executionResult.errors > 0)
+ }
+ }
+ })
+ }
+ }
}
\ No newline at end of file
diff --git a/idea/idea-repl/src/org/jetbrains/kotlin/console/ConsoleCompilerHelper.kt.193 b/idea/idea-repl/src/org/jetbrains/kotlin/console/ConsoleCompilerHelper.kt.193
new file mode 100644
index 0000000..16b639f
--- /dev/null
+++ b/idea/idea-repl/src/org/jetbrains/kotlin/console/ConsoleCompilerHelper.kt.193
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2010-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 org.jetbrains.kotlin.console
+
+import com.intellij.execution.ExecutionManager
+import com.intellij.execution.Executor
+import com.intellij.execution.ui.RunContentDescriptor
+import com.intellij.openapi.compiler.CompilerManager
+import com.intellij.openapi.module.Module
+import com.intellij.openapi.project.Project
+import com.intellij.task.ProjectTaskContext
+import com.intellij.task.ProjectTaskManager
+import com.intellij.task.ProjectTaskNotification
+import com.intellij.task.ProjectTaskResult
+
+class ConsoleCompilerHelper(
+ private val project: Project,
+ private val module: Module,
+ private val executor: Executor,
+ private val contentDescriptor: RunContentDescriptor
+) {
+
+ fun moduleIsUpToDate(): Boolean {
+ val compilerManager = CompilerManager.getInstance(project)
+ val compilerScope = compilerManager.createModuleCompileScope(module, true)
+ return compilerManager.isUpToDate(compilerScope)
+ }
+
+ fun compileModule() {
+ if (ExecutionManager.getInstance(project).contentManager.removeRunContent(executor, contentDescriptor)) {
+ ProjectTaskManager.getInstance(project).build(module).onSuccess { executionResult ->
+ if (!module.isDisposed) {
+ KotlinConsoleKeeper.getInstance(project).run(module, previousCompilationFailed = executionResult.hasErrors())
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/compat.kt b/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/compat.kt
index 1f21d3b..da39b0a 100644
--- a/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/compat.kt
+++ b/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/compat.kt
@@ -1,20 +1,20 @@
-/*
- * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
- * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
- */
-
-@file:Suppress("UNUSED_PARAMETER")
-
-package org.jetbrains.kotlin.idea.perf
-
-import com.intellij.openapi.Disposable
-import com.intellij.openapi.project.Project
-import com.intellij.testFramework.propertyBased.MadTestingUtil
-
-// BUNCH: 193
-fun enableAllInspectionsCompat(project: Project, disposable: Disposable) {
- MadTestingUtil.enableAllInspections(project, disposable)
-}
-
-// BUNCH: 193
-typealias TestApplicationManager = com.intellij.idea.IdeaTestApplication
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+@file:Suppress("UNUSED_PARAMETER")
+
+package org.jetbrains.kotlin.idea.perf
+
+import com.intellij.openapi.Disposable
+import com.intellij.openapi.project.Project
+import com.intellij.testFramework.propertyBased.MadTestingUtil
+
+// BUNCH: 193
+fun enableAllInspectionsCompat(project: Project, disposable: Disposable) {
+ MadTestingUtil.enableAllInspections(project)
+}
+
+// BUNCH: 193
+typealias TestApplicationManager = com.intellij.testFramework.TestApplicationManager
\ No newline at end of file
diff --git a/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/compat.kt.193 b/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/compat.kt.193
new file mode 100644
index 0000000..257dede
--- /dev/null
+++ b/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/compat.kt.193
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+@file:Suppress("UNUSED_PARAMETER")
+
+package org.jetbrains.kotlin.idea.perf
+
+import com.intellij.openapi.Disposable
+import com.intellij.openapi.project.Project
+import com.intellij.testFramework.propertyBased.MadTestingUtil
+
+// BUNCH: 193
+fun enableAllInspectionsCompat(project: Project, disposable: Disposable) {
+ MadTestingUtil.enableAllInspections(project, disposable)
+}
+
+// BUNCH: 193
+typealias TestApplicationManager = com.intellij.idea.IdeaTestApplication
diff --git a/idea/performanceTests/test/org/jetbrains/kotlin/idea/testFramework/compat.kt b/idea/performanceTests/test/org/jetbrains/kotlin/idea/testFramework/compat.kt
index 042b430..324da4c 100644
--- a/idea/performanceTests/test/org/jetbrains/kotlin/idea/testFramework/compat.kt
+++ b/idea/performanceTests/test/org/jetbrains/kotlin/idea/testFramework/compat.kt
@@ -1,15 +1,15 @@
-/*
- * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
- * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
- */
-
-package org.jetbrains.kotlin.idea.testFramework
-
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.project.ex.ProjectManagerEx
-
-// BUNCH: 193
-fun ProjectManagerEx.forceCloseProjectEx(project: Project, dispose: Boolean): Boolean {
- if (!dispose) error("dispose should be true")
- return this.forceCloseProject(project, true)
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.testFramework
+
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.project.ex.ProjectManagerEx
+
+// BUNCH: 193
+fun ProjectManagerEx.forceCloseProjectEx(project: Project, dispose: Boolean): Boolean {
+ if (!dispose) error("dispose should be true")
+ return this.forceCloseProject(project)
}
\ No newline at end of file
diff --git a/idea/performanceTests/test/org/jetbrains/kotlin/idea/testFramework/compat.kt.193 b/idea/performanceTests/test/org/jetbrains/kotlin/idea/testFramework/compat.kt.193
new file mode 100644
index 0000000..a6ebabb
--- /dev/null
+++ b/idea/performanceTests/test/org/jetbrains/kotlin/idea/testFramework/compat.kt.193
@@ -0,0 +1,15 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.testFramework
+
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.project.ex.ProjectManagerEx
+
+// BUNCH: 193
+fun ProjectManagerEx.forceCloseProjectEx(project: Project, dispose: Boolean): Boolean {
+ if (!dispose) error("dispose should be true")
+ return this.forceCloseProject(project, true)
+}
\ No newline at end of file
diff --git a/idea/performanceTests/test/org/jetbrains/kotlin/idea/testFramework/gradleRoutines.kt b/idea/performanceTests/test/org/jetbrains/kotlin/idea/testFramework/gradleRoutines.kt
index 9bc9ff4..2a00da3 100644
--- a/idea/performanceTests/test/org/jetbrains/kotlin/idea/testFramework/gradleRoutines.kt
+++ b/idea/performanceTests/test/org/jetbrains/kotlin/idea/testFramework/gradleRoutines.kt
@@ -1,72 +1,70 @@
-/*
- * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
- * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
- */
-
-package org.jetbrains.kotlin.idea.testFramework
-
-import com.intellij.openapi.externalSystem.importing.ImportSpecBuilder
-import com.intellij.openapi.externalSystem.service.execution.ProgressExecutionMode
-import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManagerImpl
-import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
-import com.intellij.openapi.externalSystem.util.ExternalSystemUtil
-import com.intellij.openapi.project.DumbService
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.roots.ProjectRootManager
-import org.jetbrains.plugins.gradle.service.project.open.setupGradleSettings
-import org.jetbrains.plugins.gradle.settings.GradleProjectSettings
-import org.jetbrains.plugins.gradle.util.GradleConstants
-import org.jetbrains.plugins.gradle.util.GradleLog
-import java.io.File
-import kotlin.test.assertNotNull
-
-fun refreshGradleProject(projectPath: String, project: Project) {
- _importProject(File(projectPath).absolutePath, project)
-
- dispatchAllInvocationEvents()
-}
-
-/**
- * inspired by org.jetbrains.plugins.gradle.service.project.open.importProject(projectDirectory, project)
- */
-private fun _importProject(projectPath: String, project: Project) {
- GradleLog.LOG.info("Import project at $projectPath")
- val projectSdk = ProjectRootManager.getInstance(project).projectSdk
- assertNotNull(projectSdk, "project SDK not found for ${project.name} at $projectPath")
- val gradleProjectSettings = GradleProjectSettings()
- setupGradleSettings(gradleProjectSettings, projectPath, project, projectSdk)
-
- _attachGradleProjectAndRefresh(gradleProjectSettings, project)
-}
-
-/**
- * inspired by org.jetbrains.plugins.gradle.service.project.open.attachGradleProjectAndRefresh(gradleProjectSettings, project)
- * except everything is MODAL_SYNC
- */
-private fun _attachGradleProjectAndRefresh(
- gradleProjectSettings: GradleProjectSettings,
- project: Project
-) {
- val externalProjectPath = gradleProjectSettings.externalProjectPath
- ExternalProjectsManagerImpl.getInstance(project).runWhenInitialized {
- DumbService.getInstance(project).runWhenSmart {
- ExternalSystemUtil.ensureToolWindowInitialized(project, GradleConstants.SYSTEM_ID)
- }
- }
-
- ExternalProjectsManagerImpl.disableProjectWatcherAutoUpdate(project)
- val settings = ExternalSystemApiUtil.getSettings(project, GradleConstants.SYSTEM_ID)
- if (settings.getLinkedProjectSettings(externalProjectPath) == null) {
- settings.linkProject(gradleProjectSettings)
- }
-
- StatefulTestGradleProjectRefreshCallback(externalProjectPath, project).use { callback ->
- ExternalSystemUtil.refreshProject(
- externalProjectPath,
- ImportSpecBuilder(project, GradleConstants.SYSTEM_ID)
- .use(ProgressExecutionMode.MODAL_SYNC)
- .callback(callback)
- .build()
- )
- }
-}
+/*
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.testFramework
+
+import com.intellij.openapi.externalSystem.importing.ImportSpecBuilder
+import com.intellij.openapi.externalSystem.service.execution.ProgressExecutionMode
+import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManagerImpl
+import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
+import com.intellij.openapi.externalSystem.util.ExternalSystemUtil
+import com.intellij.openapi.project.DumbService
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.roots.ProjectRootManager
+import org.jetbrains.plugins.gradle.service.project.open.setupGradleSettings
+import org.jetbrains.plugins.gradle.settings.GradleProjectSettings
+import org.jetbrains.plugins.gradle.util.GradleConstants
+import org.jetbrains.plugins.gradle.util.GradleLog
+import java.io.File
+import kotlin.test.assertNotNull
+
+fun refreshGradleProject(projectPath: String, project: Project) {
+ _importProject(File(projectPath).absolutePath, project)
+
+ dispatchAllInvocationEvents()
+}
+
+/**
+ * inspired by org.jetbrains.plugins.gradle.service.project.open.importProject(projectDirectory, project)
+ */
+private fun _importProject(projectPath: String, project: Project) {
+ GradleLog.LOG.info("Import project at $projectPath")
+ val projectSdk = ProjectRootManager.getInstance(project).projectSdk
+ assertNotNull(projectSdk, "project SDK not found for ${project.name} at $projectPath")
+ val gradleProjectSettings = GradleProjectSettings()
+ setupGradleSettings(gradleProjectSettings, projectPath, project, projectSdk)
+
+ _attachGradleProjectAndRefresh(gradleProjectSettings, project)
+}
+
+/**
+ * inspired by org.jetbrains.plugins.gradle.service.project.open.attachGradleProjectAndRefresh(gradleProjectSettings, project)
+ * except everything is MODAL_SYNC
+ */
+private fun _attachGradleProjectAndRefresh(
+ gradleProjectSettings: GradleProjectSettings,
+ project: Project
+) {
+ val externalProjectPath = gradleProjectSettings.externalProjectPath
+ ExternalProjectsManagerImpl.getInstance(project).runWhenInitialized {
+ DumbService.getInstance(project).runWhenSmart {
+ ExternalSystemUtil.ensureToolWindowInitialized(project, GradleConstants.SYSTEM_ID)
+ }
+ }
+ val settings = ExternalSystemApiUtil.getSettings(project, GradleConstants.SYSTEM_ID)
+ if (settings.getLinkedProjectSettings(externalProjectPath) == null) {
+ settings.linkProject(gradleProjectSettings)
+ }
+
+ StatefulTestGradleProjectRefreshCallback(externalProjectPath, project).use { callback ->
+ ExternalSystemUtil.refreshProject(
+ externalProjectPath,
+ ImportSpecBuilder(project, GradleConstants.SYSTEM_ID)
+ .use(ProgressExecutionMode.MODAL_SYNC)
+ .callback(callback)
+ .build()
+ )
+ }
+}
diff --git a/idea/performanceTests/test/org/jetbrains/kotlin/idea/testFramework/gradleRoutines.kt.193 b/idea/performanceTests/test/org/jetbrains/kotlin/idea/testFramework/gradleRoutines.kt.193
new file mode 100644
index 0000000..517f5de
--- /dev/null
+++ b/idea/performanceTests/test/org/jetbrains/kotlin/idea/testFramework/gradleRoutines.kt.193
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.testFramework
+
+import com.intellij.openapi.externalSystem.importing.ImportSpecBuilder
+import com.intellij.openapi.externalSystem.service.execution.ProgressExecutionMode
+import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManagerImpl
+import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
+import com.intellij.openapi.externalSystem.util.ExternalSystemUtil
+import com.intellij.openapi.project.DumbService
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.roots.ProjectRootManager
+import org.jetbrains.plugins.gradle.service.project.open.setupGradleSettings
+import org.jetbrains.plugins.gradle.settings.GradleProjectSettings
+import org.jetbrains.plugins.gradle.util.GradleConstants
+import org.jetbrains.plugins.gradle.util.GradleLog
+import java.io.File
+import kotlin.test.assertNotNull
+
+fun refreshGradleProject(projectPath: String, project: Project) {
+ _importProject(File(projectPath).absolutePath, project)
+
+ dispatchAllInvocationEvents()
+}
+
+/**
+ * inspired by org.jetbrains.plugins.gradle.service.project.open.importProject(projectDirectory, project)
+ */
+private fun _importProject(projectPath: String, project: Project) {
+ GradleLog.LOG.info("Import project at $projectPath")
+ val projectSdk = ProjectRootManager.getInstance(project).projectSdk
+ assertNotNull(projectSdk, "project SDK not found for ${project.name} at $projectPath")
+ val gradleProjectSettings = GradleProjectSettings()
+ setupGradleSettings(gradleProjectSettings, projectPath, project, projectSdk)
+
+ _attachGradleProjectAndRefresh(gradleProjectSettings, project)
+}
+
+/**
+ * inspired by org.jetbrains.plugins.gradle.service.project.open.attachGradleProjectAndRefresh(gradleProjectSettings, project)
+ * except everything is MODAL_SYNC
+ */
+private fun _attachGradleProjectAndRefresh(
+ gradleProjectSettings: GradleProjectSettings,
+ project: Project
+) {
+ val externalProjectPath = gradleProjectSettings.externalProjectPath
+ ExternalProjectsManagerImpl.getInstance(project).runWhenInitialized {
+ DumbService.getInstance(project).runWhenSmart {
+ ExternalSystemUtil.ensureToolWindowInitialized(project, GradleConstants.SYSTEM_ID)
+ }
+ }
+
+ ExternalProjectsManagerImpl.disableProjectWatcherAutoUpdate(project)
+ val settings = ExternalSystemApiUtil.getSettings(project, GradleConstants.SYSTEM_ID)
+ if (settings.getLinkedProjectSettings(externalProjectPath) == null) {
+ settings.linkProject(gradleProjectSettings)
+ }
+
+ StatefulTestGradleProjectRefreshCallback(externalProjectPath, project).use { callback ->
+ ExternalSystemUtil.refreshProject(
+ externalProjectPath,
+ ImportSpecBuilder(project, GradleConstants.SYSTEM_ID)
+ .use(ProgressExecutionMode.MODAL_SYNC)
+ .callback(callback)
+ .build()
+ )
+ }
+}
diff --git a/idea/resources/META-INF/plugin.xml b/idea/resources/META-INF/plugin.xml
index 4e97757..ea12eb76 100644
--- a/idea/resources/META-INF/plugin.xml
+++ b/idea/resources/META-INF/plugin.xml
@@ -1,93 +1,93 @@
-<idea-plugin xmlns:xi="http://www.w3.org/2001/XInclude" version="2" url="http://kotlinlang.org" allow-bundled-update="true">
- <id>org.jetbrains.kotlin</id>
-
- <name>Kotlin</name>
- <description><![CDATA[
-The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
-<br>
-<a href="http://kotlinlang.org/docs/tutorials/getting-started.html">Getting Started in IntelliJ IDEA</a><br>
-<a href="http://kotlinlang.org/docs/tutorials/kotlin-android.html">Getting Started in Android Studio</a><br>
-<a href="http://slack.kotlinlang.org/">Public Slack</a><br>
-<a href="https://youtrack.jetbrains.com/issues/KT">Issue tracker</a><br>
-]]></description>
- <version>@snapshot@</version>
- <vendor url="http://www.jetbrains.com">JetBrains</vendor>
-
- <idea-version since-build="193.4099.13" until-build="193.*"/>
-
- <depends>com.intellij.modules.platform</depends>
-
- <depends optional="true" config-file="junit.xml">JUnit</depends>
- <depends optional="true" config-file="gradle.xml">com.intellij.gradle</depends>
- <depends optional="true" config-file="gradle-java.xml">org.jetbrains.plugins.gradle</depends>
- <depends optional="true" config-file="kotlin-gradle-testing.xml">org.jetbrains.plugins.gradle</depends>
- <depends optional="true" config-file="gradle-groovy.xml">org.intellij.groovy</depends>
- <depends optional="true" config-file="maven.xml">org.jetbrains.idea.maven</depends>
- <depends optional="true" config-file="testng-j.xml">TestNG-J</depends>
- <depends optional="true" config-file="coverage.xml">Coverage</depends>
- <depends optional="true" config-file="i18n.xml">com.intellij.java-i18n</depends>
- <depends optional="true" config-file="decompiler.xml">org.jetbrains.java.decompiler</depends>
- <depends optional="true" config-file="git4idea.xml">Git4Idea</depends>
- <depends optional="true" config-file="stream-debugger.xml">org.jetbrains.debugger.streams</depends>
-
- <!-- ULTIMATE-PLUGIN-PLACEHOLDER -->
-
- <!-- CIDR-PLUGIN-PLACEHOLDER-START -->
- <depends>com.intellij.modules.idea</depends>
- <depends>com.intellij.modules.java</depends>
- <depends optional="true" config-file="javaScriptDebug.xml">JavaScriptDebugger</depends>
- <depends optional="true" config-file="kotlin-copyright.xml">com.intellij.copyright</depends>
- <depends optional="true" config-file="injection.xml">org.intellij.intelliLang</depends>
- <!-- CIDR-PLUGIN-PLACEHOLDER-END -->
-
- <xi:include href="plugin-common.xml" xpointer="xpointer(/idea-plugin/*)"/>
-
- <!-- CIDR-PLUGIN-EXCLUDE-START -->
- <xi:include href="jvm.xml" xpointer="xpointer(/idea-plugin/*)"/>
- <!-- CIDR-PLUGIN-EXCLUDE-END -->
-
- <xi:include href="native.xml" xpointer="xpointer(/idea-plugin/*)"/>
- <xi:include href="tipsAndTricks.xml" xpointer="xpointer(/idea-plugin/*)"/>
-
- <xi:include href="extensions/ide.xml" xpointer="xpointer(/idea-plugin/*)"/>
-
- <xi:include href="kotlinx-serialization.xml" xpointer="xpointer(/idea-plugin/*)"/>
-
- <xi:include href="scripting-support.xml" xpointer="xpointer(/idea-plugin/*)"/>
-
- <extensionPoints>
- <xi:include href="extensions/compiler.xml" xpointer="xpointer(/idea-plugin/extensionPoints/*)"/>
-
- <extensionPoint qualifiedName="org.jetbrains.kotlin.pluginUpdateVerifier"
- interface="org.jetbrains.kotlin.idea.update.PluginUpdateVerifier"/>
- </extensionPoints>
-
- <xi:include href="plugin-kotlin-extensions.xml" xpointer="xpointer(/idea-plugin/*)"/>
-
- <extensions defaultExtensionNs="com.intellij.jvm">
- <declarationSearcher language="kotlin" implementationClass="org.jetbrains.kotlin.idea.jvm.KotlinDeclarationSearcher"/>
- </extensions>
-
- <extensions defaultExtensionNs="com.intellij">
- <statistics.counterUsagesCollector groupId="kotlin.gradle.target" version="2"/>
- <statistics.counterUsagesCollector groupId="kotlin.maven.target" version="3"/>
- <statistics.counterUsagesCollector groupId="kotlin.jps.target" version="3"/>
- <statistics.counterUsagesCollector groupId="kotlin.gradle.library" version="1"/>
- <statistics.counterUsagesCollector groupId="kotlin.ide.action.refactoring" version="1"/>
- <statistics.counterUsagesCollector groupId="kotlin.ide.newFileTempl" version="1"/>
- <statistics.counterUsagesCollector groupId="kotlin.ide.npwizards" version="1"/>
- <statistics.counterUsagesCollector groupId="kotlin.ide.debugger" version="2"/>
- <statistics.counterUsagesCollector groupId="kotlin.ide.j2k" version="1"/>
- <statistics.counterUsagesCollector groupId="kotlin.ide.editor" version="1"/>
- <statistics.counterUsagesCollector groupId="kotlin.ide.new.wizard" version="1"/>
- <statistics.counterUsagesCollector groupId="kotlin.gradle.performance" version="1"/>
- <statistics.projectUsagesCollector implementation="org.jetbrains.kotlin.idea.statistics.IDESettingsFUSCollector"/>
- <statistics.projectUsagesCollector implementation="org.jetbrains.kotlin.idea.formatter.KotlinFormatterUsageCollector"/>
- <statistics.projectUsagesCollector implementation="org.jetbrains.kotlin.idea.statistics.ProjectConfigurationCollector"/>
-
- <fileTypeUsageSchemaDescriptor schema="Gradle Script" implementationClass="org.jetbrains.kotlin.idea.core.script.KotlinGradleScriptFileTypeSchemaDetector"/>
-
- <completion.ml.model implementation="org.jetbrains.kotlin.idea.completion.ml.KotlinMLRankingProvider"/>
- <completion.ml.contextFeatures language="kotlin" implementationClass="org.jetbrains.kotlin.idea.completion.ml.KotlinContextFeatureProvider"/>
- </extensions>
-</idea-plugin>
+<idea-plugin xmlns:xi="http://www.w3.org/2001/XInclude" version="2" url="http://kotlinlang.org" allow-bundled-update="true">
+ <id>org.jetbrains.kotlin</id>
+
+ <name>Kotlin</name>
+ <description><![CDATA[
+The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
+<br>
+<a href="http://kotlinlang.org/docs/tutorials/getting-started.html">Getting Started in IntelliJ IDEA</a><br>
+<a href="http://kotlinlang.org/docs/tutorials/kotlin-android.html">Getting Started in Android Studio</a><br>
+<a href="http://slack.kotlinlang.org/">Public Slack</a><br>
+<a href="https://youtrack.jetbrains.com/issues/KT">Issue tracker</a><br>
+]]></description>
+ <version>@snapshot@</version>
+ <vendor url="http://www.jetbrains.com">JetBrains</vendor>
+
+ <idea-version since-build="201.4515.1" until-build="202.*"/>
+
+ <depends>com.intellij.modules.platform</depends>
+
+ <depends optional="true" config-file="junit.xml">JUnit</depends>
+ <depends optional="true" config-file="gradle.xml">com.intellij.gradle</depends>
+ <depends optional="true" config-file="gradle-java.xml">org.jetbrains.plugins.gradle</depends>
+ <depends optional="true" config-file="kotlin-gradle-testing.xml">org.jetbrains.plugins.gradle</depends>
+ <depends optional="true" config-file="gradle-groovy.xml">org.intellij.groovy</depends>
+ <depends optional="true" config-file="maven.xml">org.jetbrains.idea.maven</depends>
+ <depends optional="true" config-file="testng-j.xml">TestNG-J</depends>
+ <depends optional="true" config-file="coverage.xml">Coverage</depends>
+ <depends optional="true" config-file="i18n.xml">com.intellij.java-i18n</depends>
+ <depends optional="true" config-file="decompiler.xml">org.jetbrains.java.decompiler</depends>
+ <depends optional="true" config-file="git4idea.xml">Git4Idea</depends>
+ <depends optional="true" config-file="stream-debugger.xml">org.jetbrains.debugger.streams</depends>
+
+ <!-- ULTIMATE-PLUGIN-PLACEHOLDER -->
+
+ <!-- CIDR-PLUGIN-PLACEHOLDER-START -->
+ <depends>com.intellij.modules.idea</depends>
+ <depends>com.intellij.modules.java</depends>
+ <depends optional="true" config-file="javaScriptDebug.xml">JavaScriptDebugger</depends>
+ <depends optional="true" config-file="kotlin-copyright.xml">com.intellij.copyright</depends>
+ <depends optional="true" config-file="injection.xml">org.intellij.intelliLang</depends>
+ <!-- CIDR-PLUGIN-PLACEHOLDER-END -->
+
+ <xi:include href="plugin-common.xml" xpointer="xpointer(/idea-plugin/*)"/>
+
+ <!-- CIDR-PLUGIN-EXCLUDE-START -->
+ <xi:include href="jvm.xml" xpointer="xpointer(/idea-plugin/*)"/>
+ <!-- CIDR-PLUGIN-EXCLUDE-END -->
+
+ <xi:include href="native.xml" xpointer="xpointer(/idea-plugin/*)"/>
+ <xi:include href="tipsAndTricks.xml" xpointer="xpointer(/idea-plugin/*)"/>
+
+ <xi:include href="extensions/ide.xml" xpointer="xpointer(/idea-plugin/*)"/>
+
+ <xi:include href="kotlinx-serialization.xml" xpointer="xpointer(/idea-plugin/*)"/>
+
+ <xi:include href="scripting-support.xml" xpointer="xpointer(/idea-plugin/*)"/>
+
+ <extensionPoints>
+ <xi:include href="extensions/compiler.xml" xpointer="xpointer(/idea-plugin/extensionPoints/*)"/>
+
+ <extensionPoint qualifiedName="org.jetbrains.kotlin.pluginUpdateVerifier"
+ interface="org.jetbrains.kotlin.idea.update.PluginUpdateVerifier"/>
+ </extensionPoints>
+
+ <xi:include href="plugin-kotlin-extensions.xml" xpointer="xpointer(/idea-plugin/*)"/>
+
+ <extensions defaultExtensionNs="com.intellij.jvm">
+ <declarationSearcher language="kotlin" implementationClass="org.jetbrains.kotlin.idea.jvm.KotlinDeclarationSearcher"/>
+ </extensions>
+
+ <extensions defaultExtensionNs="com.intellij">
+ <statistics.counterUsagesCollector groupId="kotlin.gradle.target" version="2"/>
+ <statistics.counterUsagesCollector groupId="kotlin.maven.target" version="3"/>
+ <statistics.counterUsagesCollector groupId="kotlin.jps.target" version="3"/>
+ <statistics.counterUsagesCollector groupId="kotlin.gradle.library" version="1"/>
+ <statistics.counterUsagesCollector groupId="kotlin.ide.action.refactoring" version="1"/>
+ <statistics.counterUsagesCollector groupId="kotlin.ide.newFileTempl" version="1"/>
+ <statistics.counterUsagesCollector groupId="kotlin.ide.npwizards" version="1"/>
+ <statistics.counterUsagesCollector groupId="kotlin.ide.debugger" version="2"/>
+ <statistics.counterUsagesCollector groupId="kotlin.ide.j2k" version="1"/>
+ <statistics.counterUsagesCollector groupId="kotlin.ide.editor" version="1"/>
+ <statistics.counterUsagesCollector groupId="kotlin.ide.new.wizard" version="1"/>
+ <statistics.counterUsagesCollector groupId="kotlin.gradle.performance" version="1"/>
+ <statistics.projectUsagesCollector implementation="org.jetbrains.kotlin.idea.statistics.IDESettingsFUSCollector"/>
+ <statistics.projectUsagesCollector implementation="org.jetbrains.kotlin.idea.formatter.KotlinFormatterUsageCollector"/>
+ <statistics.projectUsagesCollector implementation="org.jetbrains.kotlin.idea.statistics.ProjectConfigurationCollector"/>
+
+ <fileTypeUsageSchemaDescriptor schema="Gradle Script" implementationClass="org.jetbrains.kotlin.idea.core.script.KotlinGradleScriptFileTypeSchemaDetector"/>
+
+ <completion.ml.model implementation="org.jetbrains.kotlin.idea.completion.ml.KotlinMLRankingProvider"/>
+ <suggestedRefactoringSupport language="kotlin" implementationClass="org.jetbrains.kotlin.idea.refactoring.suggested.KotlinSuggestedRefactoringSupport"/>
+ </extensions>
+</idea-plugin>
diff --git a/idea/resources/META-INF/plugin.xml.193 b/idea/resources/META-INF/plugin.xml.193
new file mode 100644
index 0000000..e8a760a
--- /dev/null
+++ b/idea/resources/META-INF/plugin.xml.193
@@ -0,0 +1,93 @@
+<idea-plugin xmlns:xi="http://www.w3.org/2001/XInclude" version="2" url="http://kotlinlang.org" allow-bundled-update="true">
+ <id>org.jetbrains.kotlin</id>
+
+ <name>Kotlin</name>
+ <description><![CDATA[
+The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
+<br>
+<a href="http://kotlinlang.org/docs/tutorials/getting-started.html">Getting Started in IntelliJ IDEA</a><br>
+<a href="http://kotlinlang.org/docs/tutorials/kotlin-android.html">Getting Started in Android Studio</a><br>
+<a href="http://slack.kotlinlang.org/">Public Slack</a><br>
+<a href="https://youtrack.jetbrains.com/issues/KT">Issue tracker</a><br>
+]]></description>
+ <version>@snapshot@</version>
+ <vendor url="http://www.jetbrains.com">JetBrains</vendor>
+
+ <idea-version since-build="193.4099.13" until-build="193.*"/>
+
+ <depends>com.intellij.modules.platform</depends>
+
+ <depends optional="true" config-file="junit.xml">JUnit</depends>
+ <depends optional="true" config-file="gradle.xml">com.intellij.gradle</depends>
+ <depends optional="true" config-file="gradle-java.xml">org.jetbrains.plugins.gradle</depends>
+ <depends optional="true" config-file="kotlin-gradle-testing.xml">org.jetbrains.plugins.gradle</depends>
+ <depends optional="true" config-file="gradle-groovy.xml">org.intellij.groovy</depends>
+ <depends optional="true" config-file="maven.xml">org.jetbrains.idea.maven</depends>
+ <depends optional="true" config-file="testng-j.xml">TestNG-J</depends>
+ <depends optional="true" config-file="coverage.xml">Coverage</depends>
+ <depends optional="true" config-file="i18n.xml">com.intellij.java-i18n</depends>
+ <depends optional="true" config-file="decompiler.xml">org.jetbrains.java.decompiler</depends>
+ <depends optional="true" config-file="git4idea.xml">Git4Idea</depends>
+ <depends optional="true" config-file="stream-debugger.xml">org.jetbrains.debugger.streams</depends>
+
+ <!-- ULTIMATE-PLUGIN-PLACEHOLDER -->
+
+ <!-- CIDR-PLUGIN-PLACEHOLDER-START -->
+ <depends>com.intellij.modules.idea</depends>
+ <depends>com.intellij.modules.java</depends>
+ <depends optional="true" config-file="javaScriptDebug.xml">JavaScriptDebugger</depends>
+ <depends optional="true" config-file="kotlin-copyright.xml">com.intellij.copyright</depends>
+ <depends optional="true" config-file="injection.xml">org.intellij.intelliLang</depends>
+ <!-- CIDR-PLUGIN-PLACEHOLDER-END -->
+
+ <xi:include href="plugin-common.xml" xpointer="xpointer(/idea-plugin/*)"/>
+
+ <!-- CIDR-PLUGIN-EXCLUDE-START -->
+ <xi:include href="jvm.xml" xpointer="xpointer(/idea-plugin/*)"/>
+ <!-- CIDR-PLUGIN-EXCLUDE-END -->
+
+ <xi:include href="native.xml" xpointer="xpointer(/idea-plugin/*)"/>
+ <xi:include href="tipsAndTricks.xml" xpointer="xpointer(/idea-plugin/*)"/>
+
+ <xi:include href="extensions/ide.xml" xpointer="xpointer(/idea-plugin/*)"/>
+
+ <xi:include href="kotlinx-serialization.xml" xpointer="xpointer(/idea-plugin/*)"/>
+
+ <xi:include href="scripting-support.xml" xpointer="xpointer(/idea-plugin/*)"/>
+
+ <extensionPoints>
+ <xi:include href="extensions/compiler.xml" xpointer="xpointer(/idea-plugin/extensionPoints/*)"/>
+
+ <extensionPoint qualifiedName="org.jetbrains.kotlin.pluginUpdateVerifier"
+ interface="org.jetbrains.kotlin.idea.update.PluginUpdateVerifier"/>
+ </extensionPoints>
+
+ <xi:include href="plugin-kotlin-extensions.xml" xpointer="xpointer(/idea-plugin/*)"/>
+
+ <extensions defaultExtensionNs="com.intellij.jvm">
+ <declarationSearcher language="kotlin" implementationClass="org.jetbrains.kotlin.idea.jvm.KotlinDeclarationSearcher"/>
+ </extensions>
+
+ <extensions defaultExtensionNs="com.intellij">
+ <statistics.counterUsagesCollector groupId="kotlin.gradle.target" version="2"/>
+ <statistics.counterUsagesCollector groupId="kotlin.maven.target" version="3"/>
+ <statistics.counterUsagesCollector groupId="kotlin.jps.target" version="3"/>
+ <statistics.counterUsagesCollector groupId="kotlin.gradle.library" version="1"/>
+ <statistics.counterUsagesCollector groupId="kotlin.ide.action.refactoring" version="1"/>
+ <statistics.counterUsagesCollector groupId="kotlin.ide.newFileTempl" version="1"/>
+ <statistics.counterUsagesCollector groupId="kotlin.ide.npwizards" version="1"/>
+ <statistics.counterUsagesCollector groupId="kotlin.ide.debugger" version="2"/>
+ <statistics.counterUsagesCollector groupId="kotlin.ide.j2k" version="1"/>
+ <statistics.counterUsagesCollector groupId="kotlin.ide.editor" version="1"/>
+ <statistics.counterUsagesCollector groupId="kotlin.ide.new.wizard" version="1"/>
+ <statistics.counterUsagesCollector groupId="kotlin.gradle.performance" version="1"/>
+ <statistics.projectUsagesCollector implementation="org.jetbrains.kotlin.idea.statistics.IDESettingsFUSCollector"/>
+ <statistics.projectUsagesCollector implementation="org.jetbrains.kotlin.idea.formatter.KotlinFormatterUsageCollector"/>
+ <statistics.projectUsagesCollector implementation="org.jetbrains.kotlin.idea.statistics.ProjectConfigurationCollector"/>
+
+ <fileTypeUsageSchemaDescriptor schema="Gradle Script" implementationClass="org.jetbrains.kotlin.idea.core.script.KotlinGradleScriptFileTypeSchemaDetector"/>
+
+ <completion.ml.model implementation="org.jetbrains.kotlin.idea.completion.ml.KotlinMLRankingProvider"/>
+ <completion.ml.contextFeatures language="kotlin" implementationClass="org.jetbrains.kotlin.idea.completion.ml.KotlinContextFeatureProvider"/>
+ </extensions>
+</idea-plugin>
diff --git a/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinRefactoringHelperForDelayedRequests.kt b/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinRefactoringHelperForDelayedRequests.kt
index fef84de..1f96d76 100644
--- a/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinRefactoringHelperForDelayedRequests.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinRefactoringHelperForDelayedRequests.kt
@@ -1,38 +1,38 @@
-/*
- * Copyright 2010-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 org.jetbrains.kotlin.idea.codeInsight
-
-import com.intellij.openapi.project.Project
-import com.intellij.refactoring.RefactoringHelper
-import com.intellij.usageView.UsageInfo
-import org.jetbrains.kotlin.idea.codeInsight.shorten.performDelayedRefactoringRequests
-import org.jetbrains.kotlin.idea.codeInsight.shorten.prepareDelayedRequests
-import org.jetbrains.kotlin.idea.util.application.runWriteAction
-
-class KotlinRefactoringHelperForDelayedRequests : RefactoringHelper<Any> {
- override fun prepareOperation(usages: Array<out UsageInfo>?): Any? {
- if (usages != null && usages.isNotEmpty()) {
- val project = usages[0].project
- prepareDelayedRequests(project)
- }
- return null
- }
-
- override fun performOperation(project: Project, operationData: Any?) {
- runWriteAction { performDelayedRefactoringRequests(project) }
- }
-}
+/*
+ * Copyright 2010-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 org.jetbrains.kotlin.idea.codeInsight
+
+import com.intellij.openapi.project.Project
+import com.intellij.refactoring.RefactoringHelper
+import com.intellij.usageView.UsageInfo
+import org.jetbrains.kotlin.idea.codeInsight.shorten.performDelayedRefactoringRequests
+import org.jetbrains.kotlin.idea.codeInsight.shorten.prepareDelayedRequests
+import org.jetbrains.kotlin.idea.util.application.runWriteAction
+
+class KotlinRefactoringHelperForDelayedRequests : RefactoringHelper<Any> {
+ override fun prepareOperation(usages: Array<out UsageInfo>): Any? {
+ if (usages.isNotEmpty()) {
+ val project = usages[0].project
+ prepareDelayedRequests(project)
+ }
+ return null
+ }
+
+ override fun performOperation(project: Project, operationData: Any?) {
+ runWriteAction { performDelayedRefactoringRequests(project) }
+ }
+}
diff --git a/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinRefactoringHelperForDelayedRequests.kt.193 b/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinRefactoringHelperForDelayedRequests.kt.193
new file mode 100644
index 0000000..3a4857c
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinRefactoringHelperForDelayedRequests.kt.193
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2010-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 org.jetbrains.kotlin.idea.codeInsight
+
+import com.intellij.openapi.project.Project
+import com.intellij.refactoring.RefactoringHelper
+import com.intellij.usageView.UsageInfo
+import org.jetbrains.kotlin.idea.codeInsight.shorten.performDelayedRefactoringRequests
+import org.jetbrains.kotlin.idea.codeInsight.shorten.prepareDelayedRequests
+import org.jetbrains.kotlin.idea.util.application.runWriteAction
+
+class KotlinRefactoringHelperForDelayedRequests : RefactoringHelper<Any> {
+ override fun prepareOperation(usages: Array<out UsageInfo>?): Any? {
+ if (usages != null && usages.isNotEmpty()) {
+ val project = usages[0].project
+ prepareDelayedRequests(project)
+ }
+ return null
+ }
+
+ override fun performOperation(project: Project, operationData: Any?) {
+ runWriteAction { performDelayedRefactoringRequests(project) }
+ }
+}
diff --git a/idea/src/org/jetbrains/kotlin/idea/findUsages/handlers/compat.kt b/idea/src/org/jetbrains/kotlin/idea/findUsages/handlers/compat.kt
index fe7b683..767b7f4 100644
--- a/idea/src/org/jetbrains/kotlin/idea/findUsages/handlers/compat.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/findUsages/handlers/compat.kt
@@ -1,14 +1,14 @@
-/*
- * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
- * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
- */
-
-package org.jetbrains.kotlin.idea.findUsages.handlers
-
-import com.intellij.slicer.SliceUsage
-import com.intellij.usageView.UsageInfo
-import com.intellij.util.Processor
-
-// BUNCH: 193
-typealias UsageInfoProcessor = Processor<UsageInfo>
-typealias SliceUsageProcessor = Processor<SliceUsage>
\ No newline at end of file
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.findUsages.handlers
+
+import com.intellij.slicer.SliceUsage
+import com.intellij.usageView.UsageInfo
+import com.intellij.util.Processor
+
+// BUNCH: 193
+typealias UsageInfoProcessor = Processor<in UsageInfo>
+typealias SliceUsageProcessor = Processor<in SliceUsage>
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/findUsages/handlers/compat.kt.193 b/idea/src/org/jetbrains/kotlin/idea/findUsages/handlers/compat.kt.193
new file mode 100644
index 0000000..bcfd1f0
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/findUsages/handlers/compat.kt.193
@@ -0,0 +1,14 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.findUsages.handlers
+
+import com.intellij.slicer.SliceUsage
+import com.intellij.usageView.UsageInfo
+import com.intellij.util.Processor
+
+// BUNCH: 193
+typealias UsageInfoProcessor = Processor<UsageInfo>
+typealias SliceUsageProcessor = Processor<SliceUsage>
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/hierarchy/calls/compat.kt b/idea/src/org/jetbrains/kotlin/idea/hierarchy/calls/compat.kt
index 43d74d7..0ca98cd 100644
--- a/idea/src/org/jetbrains/kotlin/idea/hierarchy/calls/compat.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/hierarchy/calls/compat.kt
@@ -1,33 +1,34 @@
-/*
- * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
- * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
- */
-
-@file:Suppress("TYPEALIAS_EXPANSION_DEPRECATION", "DEPRECATION", "UnstableApiUsage")
-
-package org.jetbrains.kotlin.idea.hierarchy.calls
-
-import com.intellij.ide.hierarchy.call.CalleeMethodsTreeStructure
-import com.intellij.ide.hierarchy.call.CallerMethodsTreeStructure
-import com.intellij.openapi.project.Project
-import com.intellij.psi.PsiMethod
-
-// BUNCH: 193
-typealias HierarchyNodeDescriptor = com.intellij.ide.hierarchy.HierarchyNodeDescriptor
-typealias HierarchyTreeStructure = com.intellij.ide.hierarchy.HierarchyTreeStructure
-typealias CallHierarchyBrowserBase = com.intellij.ide.hierarchy.CallHierarchyBrowserBase
-typealias HierarchyScopeType = String
-typealias HierarchyBrowserBaseEx = com.intellij.ide.hierarchy.HierarchyBrowserBaseEx
-typealias MethodHierarchyBrowserBase = com.intellij.ide.hierarchy.MethodHierarchyBrowserBase
-
-fun getCallerTypeCompat(): String = CallHierarchyBrowserBase.CALLER_TYPE
-fun getCalleeTypeCompat(): String = CallHierarchyBrowserBase.CALLEE_TYPE
-fun getMethodTypeCompat(): String = MethodHierarchyBrowserBase.METHOD_TYPE
-
-fun createCallerMethodsTreeStructure(project: Project, method: PsiMethod, scopeType: String): CallerMethodsTreeStructure {
- return CallerMethodsTreeStructure(project, method, scopeType)
-}
-
-fun createCalleeMethodsTreeStructure(project: Project, method: PsiMethod, scopeType: String): CalleeMethodsTreeStructure {
- return CalleeMethodsTreeStructure(project, method, scopeType)
-}
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+@file:Suppress("TYPEALIAS_EXPANSION_DEPRECATION", "DEPRECATION")
+
+package org.jetbrains.kotlin.idea.hierarchy.calls
+
+import com.intellij.ide.hierarchy.call.CalleeMethodsTreeStructure
+import com.intellij.ide.hierarchy.call.CallerMethodsTreeStructure
+import com.intellij.openapi.project.Project
+import com.intellij.psi.PsiMember
+import com.intellij.psi.PsiMethod
+
+// BUNCH: 193
+typealias HierarchyNodeDescriptor = com.intellij.ide.hierarchy.newAPI.HierarchyNodeDescriptor
+typealias HierarchyTreeStructure = com.intellij.ide.hierarchy.newAPI.HierarchyTreeStructure
+typealias CallHierarchyBrowserBase = com.intellij.ide.hierarchy.newAPI.CallHierarchyBrowserBase
+typealias HierarchyScopeType = com.intellij.ide.hierarchy.newAPI.HierarchyScopeType
+typealias HierarchyBrowserBaseEx = com.intellij.ide.hierarchy.newAPI.HierarchyBrowserBaseEx
+typealias MethodHierarchyBrowserBase = com.intellij.ide.hierarchy.newAPI.MethodHierarchyBrowserBase
+
+fun getCallerTypeCompat() = CallHierarchyBrowserBase.getCallerType()
+fun getCalleeTypeCompat() = CallHierarchyBrowserBase.getCalleeType()
+fun getMethodTypeCompat() = MethodHierarchyBrowserBase.getMethodType()
+
+fun createCallerMethodsTreeStructure(project: Project, method: PsiMethod, scopeType: String): CallerMethodsTreeStructure {
+ return CallerMethodsTreeStructure(project, method as PsiMember, scopeType)
+}
+
+fun createCalleeMethodsTreeStructure(project: Project, method: PsiMethod, scopeType: String): CalleeMethodsTreeStructure {
+ return CalleeMethodsTreeStructure(project, method as PsiMember, scopeType)
+}
diff --git a/idea/src/org/jetbrains/kotlin/idea/hierarchy/calls/compat.kt.193 b/idea/src/org/jetbrains/kotlin/idea/hierarchy/calls/compat.kt.193
new file mode 100644
index 0000000..70426fc
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/hierarchy/calls/compat.kt.193
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+@file:Suppress("TYPEALIAS_EXPANSION_DEPRECATION", "DEPRECATION", "UnstableApiUsage")
+
+package org.jetbrains.kotlin.idea.hierarchy.calls
+
+import com.intellij.ide.hierarchy.call.CalleeMethodsTreeStructure
+import com.intellij.ide.hierarchy.call.CallerMethodsTreeStructure
+import com.intellij.openapi.project.Project
+import com.intellij.psi.PsiMethod
+
+// BUNCH: 193
+typealias HierarchyNodeDescriptor = com.intellij.ide.hierarchy.HierarchyNodeDescriptor
+typealias HierarchyTreeStructure = com.intellij.ide.hierarchy.HierarchyTreeStructure
+typealias CallHierarchyBrowserBase = com.intellij.ide.hierarchy.CallHierarchyBrowserBase
+typealias HierarchyScopeType = String
+typealias HierarchyBrowserBaseEx = com.intellij.ide.hierarchy.HierarchyBrowserBaseEx
+typealias MethodHierarchyBrowserBase = com.intellij.ide.hierarchy.MethodHierarchyBrowserBase
+
+fun getCallerTypeCompat(): String = CallHierarchyBrowserBase.CALLER_TYPE
+fun getCalleeTypeCompat(): String = CallHierarchyBrowserBase.CALLEE_TYPE
+fun getMethodTypeCompat(): String = MethodHierarchyBrowserBase.METHOD_TYPE
+
+fun createCallerMethodsTreeStructure(project: Project, method: PsiMethod, scopeType: String): CallerMethodsTreeStructure {
+ return CallerMethodsTreeStructure(project, method, scopeType)
+}
+
+fun createCalleeMethodsTreeStructure(project: Project, method: PsiMethod, scopeType: String): CalleeMethodsTreeStructure {
+ return CalleeMethodsTreeStructure(project, method, scopeType)
+}
diff --git a/idea/src/org/jetbrains/kotlin/idea/navigationToolbar/KotlinNavBarModelExtension.kt b/idea/src/org/jetbrains/kotlin/idea/navigationToolbar/KotlinNavBarModelExtension.kt
index a63bdfe..b039d18 100644
--- a/idea/src/org/jetbrains/kotlin/idea/navigationToolbar/KotlinNavBarModelExtension.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/navigationToolbar/KotlinNavBarModelExtension.kt
@@ -1,27 +1,27 @@
-/*
- * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
- * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
- */
-
-package org.jetbrains.kotlin.idea.navigationToolbar
-
-import com.intellij.ide.navigationToolbar.AbstractNavBarModelExtension
-import com.intellij.psi.PsiElement
-import org.jetbrains.kotlin.idea.KotlinIconProvider
-import org.jetbrains.kotlin.psi.KtClassOrObject
-import org.jetbrains.kotlin.psi.KtFile
-
-class KotlinNavBarModelExtension : AbstractNavBarModelExtension() {
- override fun getPresentableText(item: Any?): String? {
- return when (item) {
- is KtClassOrObject -> item.name ?: "unknown"
- else -> null
- }
- }
-
- override fun adjustElement(psiElement: PsiElement?): PsiElement? {
- val containingFile = psiElement?.containingFile as? KtFile ?: return psiElement
- if (containingFile.isScript()) return psiElement
- return KotlinIconProvider.getSingleClass(containingFile) ?: psiElement
- }
-}
+/*
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.navigationToolbar
+
+import com.intellij.ide.navigationToolbar.AbstractNavBarModelExtension
+import com.intellij.psi.PsiElement
+import org.jetbrains.kotlin.idea.KotlinIconProvider
+import org.jetbrains.kotlin.psi.KtClassOrObject
+import org.jetbrains.kotlin.psi.KtFile
+
+class KotlinNavBarModelExtension : AbstractNavBarModelExtension() {
+ override fun getPresentableText(item: Any?): String? {
+ return when (item) {
+ is KtClassOrObject -> item.name ?: "unknown"
+ else -> null
+ }
+ }
+
+ override fun adjustElement(psiElement: PsiElement): PsiElement? {
+ val containingFile = psiElement.containingFile as? KtFile ?: return psiElement
+ if (containingFile.isScript()) return psiElement
+ return KotlinIconProvider.getSingleClass(containingFile) ?: psiElement
+ }
+}
diff --git a/idea/src/org/jetbrains/kotlin/idea/navigationToolbar/KotlinNavBarModelExtension.kt.193 b/idea/src/org/jetbrains/kotlin/idea/navigationToolbar/KotlinNavBarModelExtension.kt.193
new file mode 100644
index 0000000..5c037fe
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/navigationToolbar/KotlinNavBarModelExtension.kt.193
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.navigationToolbar
+
+import com.intellij.ide.navigationToolbar.AbstractNavBarModelExtension
+import com.intellij.psi.PsiElement
+import org.jetbrains.kotlin.idea.KotlinIconProvider
+import org.jetbrains.kotlin.psi.KtClassOrObject
+import org.jetbrains.kotlin.psi.KtFile
+
+class KotlinNavBarModelExtension : AbstractNavBarModelExtension() {
+ override fun getPresentableText(item: Any?): String? {
+ return when (item) {
+ is KtClassOrObject -> item.name ?: "unknown"
+ else -> null
+ }
+ }
+
+ override fun adjustElement(psiElement: PsiElement?): PsiElement? {
+ val containingFile = psiElement?.containingFile as? KtFile ?: return psiElement
+ if (containingFile.isScript()) return psiElement
+ return KotlinIconProvider.getSingleClass(containingFile) ?: psiElement
+ }
+}
diff --git a/idea/src/org/jetbrains/kotlin/idea/projectView/KtDeclarationTreeNode.java b/idea/src/org/jetbrains/kotlin/idea/projectView/KtDeclarationTreeNode.java
index a049dbb..971d47f 100644
--- a/idea/src/org/jetbrains/kotlin/idea/projectView/KtDeclarationTreeNode.java
+++ b/idea/src/org/jetbrains/kotlin/idea/projectView/KtDeclarationTreeNode.java
@@ -1,110 +1,110 @@
-/*
- * Copyright 2010-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 org.jetbrains.kotlin.idea.projectView;
-
-import com.intellij.application.options.CodeStyle;
-import com.intellij.ide.projectView.PresentationData;
-import com.intellij.ide.projectView.ViewSettings;
-import com.intellij.ide.projectView.impl.nodes.AbstractPsiBasedNode;
-import com.intellij.ide.util.treeView.AbstractTreeNode;
-import com.intellij.openapi.project.Project;
-import com.intellij.psi.PsiElement;
-import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings;
-import org.jetbrains.kotlin.psi.*;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-
-public class KtDeclarationTreeNode extends AbstractPsiBasedNode<KtDeclaration> {
- public static final String CLASS_INITIALIZER = "<class initializer>";
-
- protected KtDeclarationTreeNode(Project project, KtDeclaration ktDeclaration, ViewSettings viewSettings) {
- super(project, ktDeclaration, viewSettings);
- }
-
- @Override
- protected PsiElement extractPsiFromValue() {
- return getValue();
- }
-
- @Override
- protected Collection<AbstractTreeNode> getChildrenImpl() {
- return Collections.emptyList();
- }
-
- @Override
- protected void updateImpl(PresentationData data) {
- KtDeclaration declaration = getValue();
- if (declaration != null) {
- String text = declaration instanceof KtAnonymousInitializer ? CLASS_INITIALIZER : declaration.getName();
- if (text == null) return;
-
- KotlinCodeStyleSettings settings = CodeStyle.getSettings(getProject())
- .getCustomSettings(KotlinCodeStyleSettings.class);
-
- if (declaration instanceof KtProperty) {
- KtProperty property = (KtProperty) declaration;
- KtTypeReference ref = property.getTypeReference();
- if (ref != null) {
- if (settings.SPACE_BEFORE_TYPE_COLON) text += " ";
- text += ":";
- if (settings.SPACE_AFTER_TYPE_COLON) text += " ";
- text += ref.getText();
- }
- }
- else if (declaration instanceof KtFunction) {
- KtFunction function = (KtFunction) declaration;
- KtTypeReference receiverTypeRef = function.getReceiverTypeReference();
- if (receiverTypeRef != null) {
- text = receiverTypeRef.getText() + "." + text;
- }
- text += "(";
- List<KtParameter> parameters = function.getValueParameters();
- for (KtParameter parameter : parameters) {
- if (parameter.getName() != null) {
- text += parameter.getName();
- if (settings.SPACE_BEFORE_TYPE_COLON) text += " ";
- text += ":";
- if (settings.SPACE_AFTER_TYPE_COLON) text += " ";
- }
- KtTypeReference typeReference = parameter.getTypeReference();
- if (typeReference != null) {
- text += typeReference.getText();
- }
- text += ", ";
- }
- if (parameters.size() > 0) text = text.substring(0, text.length() - 2);
- text += ")";
- KtTypeReference typeReference = function.getTypeReference();
- if (typeReference != null) {
- if (settings.SPACE_BEFORE_TYPE_COLON) text += " ";
- text += ":";
- if (settings.SPACE_AFTER_TYPE_COLON) text += " ";
- text += typeReference.getText();
- }
- }
-
- data.setPresentableText(text);
- }
- }
-
- @Override
- protected boolean isDeprecated() {
- return KtPsiUtil.isDeprecated(getValue());
- }
-}
+/*
+ * Copyright 2010-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 org.jetbrains.kotlin.idea.projectView;
+
+import com.intellij.application.options.CodeStyle;
+import com.intellij.ide.projectView.PresentationData;
+import com.intellij.ide.projectView.ViewSettings;
+import com.intellij.ide.projectView.impl.nodes.AbstractPsiBasedNode;
+import com.intellij.ide.util.treeView.AbstractTreeNode;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiElement;
+import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings;
+import org.jetbrains.kotlin.psi.*;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+public class KtDeclarationTreeNode extends AbstractPsiBasedNode<KtDeclaration> {
+ public static final String CLASS_INITIALIZER = "<class initializer>";
+
+ protected KtDeclarationTreeNode(Project project, KtDeclaration ktDeclaration, ViewSettings viewSettings) {
+ super(project, ktDeclaration, viewSettings);
+ }
+
+ @Override
+ protected PsiElement extractPsiFromValue() {
+ return getValue();
+ }
+
+ @Override
+ protected Collection<AbstractTreeNode<?>> getChildrenImpl() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ protected void updateImpl(PresentationData data) {
+ KtDeclaration declaration = getValue();
+ if (declaration != null) {
+ String text = declaration instanceof KtAnonymousInitializer ? CLASS_INITIALIZER : declaration.getName();
+ if (text == null) return;
+
+ KotlinCodeStyleSettings settings = CodeStyle.getSettings(getProject())
+ .getCustomSettings(KotlinCodeStyleSettings.class);
+
+ if (declaration instanceof KtProperty) {
+ KtProperty property = (KtProperty) declaration;
+ KtTypeReference ref = property.getTypeReference();
+ if (ref != null) {
+ if (settings.SPACE_BEFORE_TYPE_COLON) text += " ";
+ text += ":";
+ if (settings.SPACE_AFTER_TYPE_COLON) text += " ";
+ text += ref.getText();
+ }
+ }
+ else if (declaration instanceof KtFunction) {
+ KtFunction function = (KtFunction) declaration;
+ KtTypeReference receiverTypeRef = function.getReceiverTypeReference();
+ if (receiverTypeRef != null) {
+ text = receiverTypeRef.getText() + "." + text;
+ }
+ text += "(";
+ List<KtParameter> parameters = function.getValueParameters();
+ for (KtParameter parameter : parameters) {
+ if (parameter.getName() != null) {
+ text += parameter.getName();
+ if (settings.SPACE_BEFORE_TYPE_COLON) text += " ";
+ text += ":";
+ if (settings.SPACE_AFTER_TYPE_COLON) text += " ";
+ }
+ KtTypeReference typeReference = parameter.getTypeReference();
+ if (typeReference != null) {
+ text += typeReference.getText();
+ }
+ text += ", ";
+ }
+ if (parameters.size() > 0) text = text.substring(0, text.length() - 2);
+ text += ")";
+ KtTypeReference typeReference = function.getTypeReference();
+ if (typeReference != null) {
+ if (settings.SPACE_BEFORE_TYPE_COLON) text += " ";
+ text += ":";
+ if (settings.SPACE_AFTER_TYPE_COLON) text += " ";
+ text += typeReference.getText();
+ }
+ }
+
+ data.setPresentableText(text);
+ }
+ }
+
+ @Override
+ protected boolean isDeprecated() {
+ return KtPsiUtil.isDeprecated(getValue());
+ }
+}
diff --git a/idea/src/org/jetbrains/kotlin/idea/projectView/KtDeclarationTreeNode.java.193 b/idea/src/org/jetbrains/kotlin/idea/projectView/KtDeclarationTreeNode.java.193
new file mode 100644
index 0000000..60faddc
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/projectView/KtDeclarationTreeNode.java.193
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2010-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 org.jetbrains.kotlin.idea.projectView;
+
+import com.intellij.application.options.CodeStyle;
+import com.intellij.ide.projectView.PresentationData;
+import com.intellij.ide.projectView.ViewSettings;
+import com.intellij.ide.projectView.impl.nodes.AbstractPsiBasedNode;
+import com.intellij.ide.util.treeView.AbstractTreeNode;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiElement;
+import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings;
+import org.jetbrains.kotlin.psi.*;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+public class KtDeclarationTreeNode extends AbstractPsiBasedNode<KtDeclaration> {
+ public static final String CLASS_INITIALIZER = "<class initializer>";
+
+ protected KtDeclarationTreeNode(Project project, KtDeclaration ktDeclaration, ViewSettings viewSettings) {
+ super(project, ktDeclaration, viewSettings);
+ }
+
+ @Override
+ protected PsiElement extractPsiFromValue() {
+ return getValue();
+ }
+
+ @Override
+ protected Collection<AbstractTreeNode> getChildrenImpl() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ protected void updateImpl(PresentationData data) {
+ KtDeclaration declaration = getValue();
+ if (declaration != null) {
+ String text = declaration instanceof KtAnonymousInitializer ? CLASS_INITIALIZER : declaration.getName();
+ if (text == null) return;
+
+ KotlinCodeStyleSettings settings = CodeStyle.getSettings(getProject())
+ .getCustomSettings(KotlinCodeStyleSettings.class);
+
+ if (declaration instanceof KtProperty) {
+ KtProperty property = (KtProperty) declaration;
+ KtTypeReference ref = property.getTypeReference();
+ if (ref != null) {
+ if (settings.SPACE_BEFORE_TYPE_COLON) text += " ";
+ text += ":";
+ if (settings.SPACE_AFTER_TYPE_COLON) text += " ";
+ text += ref.getText();
+ }
+ }
+ else if (declaration instanceof KtFunction) {
+ KtFunction function = (KtFunction) declaration;
+ KtTypeReference receiverTypeRef = function.getReceiverTypeReference();
+ if (receiverTypeRef != null) {
+ text = receiverTypeRef.getText() + "." + text;
+ }
+ text += "(";
+ List<KtParameter> parameters = function.getValueParameters();
+ for (KtParameter parameter : parameters) {
+ if (parameter.getName() != null) {
+ text += parameter.getName();
+ if (settings.SPACE_BEFORE_TYPE_COLON) text += " ";
+ text += ":";
+ if (settings.SPACE_AFTER_TYPE_COLON) text += " ";
+ }
+ KtTypeReference typeReference = parameter.getTypeReference();
+ if (typeReference != null) {
+ text += typeReference.getText();
+ }
+ text += ", ";
+ }
+ if (parameters.size() > 0) text = text.substring(0, text.length() - 2);
+ text += ")";
+ KtTypeReference typeReference = function.getTypeReference();
+ if (typeReference != null) {
+ if (settings.SPACE_BEFORE_TYPE_COLON) text += " ";
+ text += ":";
+ if (settings.SPACE_AFTER_TYPE_COLON) text += " ";
+ text += typeReference.getText();
+ }
+ }
+
+ data.setPresentableText(text);
+ }
+ }
+
+ @Override
+ protected boolean isDeprecated() {
+ return KtPsiUtil.isDeprecated(getValue());
+ }
+}
diff --git a/idea/src/org/jetbrains/kotlin/idea/projectView/KtFileTreeNode.java b/idea/src/org/jetbrains/kotlin/idea/projectView/KtFileTreeNode.java
index 2a13bc8..901967a 100644
--- a/idea/src/org/jetbrains/kotlin/idea/projectView/KtFileTreeNode.java
+++ b/idea/src/org/jetbrains/kotlin/idea/projectView/KtFileTreeNode.java
@@ -1,63 +1,63 @@
-/*
- * Copyright 2010-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 org.jetbrains.kotlin.idea.projectView;
-
-import com.intellij.ide.projectView.ViewSettings;
-import com.intellij.ide.projectView.impl.nodes.PsiFileNode;
-import com.intellij.ide.util.treeView.AbstractTreeNode;
-import com.intellij.openapi.project.Project;
-import org.jetbrains.kotlin.psi.KtClassOrObject;
-import org.jetbrains.kotlin.psi.KtDeclaration;
-import org.jetbrains.kotlin.psi.KtFile;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-
-public class KtFileTreeNode extends PsiFileNode {
- public KtFileTreeNode(Project project, KtFile value, ViewSettings viewSettings) {
- super(project, value, viewSettings);
- }
-
- public final KtFile getKtFile() {
- return (KtFile) getValue();
- }
-
- @Override
- public Collection<AbstractTreeNode> getChildrenImpl() {
- KtFile file = (KtFile) getValue();
-
- if (file == null) return Collections.emptyList();
- ArrayList<AbstractTreeNode> result = new ArrayList<AbstractTreeNode>();
-
- if (getSettings().isShowMembers()) {
- @SuppressWarnings("ConstantConditions") List<KtDeclaration> declarations = (file.isScript() ? file.getScript() : file).getDeclarations();
-
- for (KtDeclaration declaration : declarations) {
- if (declaration instanceof KtClassOrObject) {
- result.add(new KtClassOrObjectTreeNode(file.getProject(), (KtClassOrObject) declaration, getSettings()));
- }
- else if (getSettings().isShowMembers()) {
- result.add(new KtDeclarationTreeNode(getProject(), declaration, getSettings()));
- }
- }
- }
-
- return result;
- }
-}
+/*
+ * Copyright 2010-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 org.jetbrains.kotlin.idea.projectView;
+
+import com.intellij.ide.projectView.ViewSettings;
+import com.intellij.ide.projectView.impl.nodes.PsiFileNode;
+import com.intellij.ide.util.treeView.AbstractTreeNode;
+import com.intellij.openapi.project.Project;
+import org.jetbrains.kotlin.psi.KtClassOrObject;
+import org.jetbrains.kotlin.psi.KtDeclaration;
+import org.jetbrains.kotlin.psi.KtFile;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+public class KtFileTreeNode extends PsiFileNode {
+ public KtFileTreeNode(Project project, KtFile value, ViewSettings viewSettings) {
+ super(project, value, viewSettings);
+ }
+
+ public final KtFile getKtFile() {
+ return (KtFile) getValue();
+ }
+
+ @Override
+ public Collection<AbstractTreeNode<?>> getChildrenImpl() {
+ KtFile file = (KtFile) getValue();
+
+ if (file == null) return Collections.emptyList();
+ ArrayList<AbstractTreeNode<?>> result = new ArrayList<>();
+
+ if (getSettings().isShowMembers()) {
+ @SuppressWarnings("ConstantConditions") List<KtDeclaration> declarations = (file.isScript() ? file.getScript() : file).getDeclarations();
+
+ for (KtDeclaration declaration : declarations) {
+ if (declaration instanceof KtClassOrObject) {
+ result.add(new KtClassOrObjectTreeNode(file.getProject(), (KtClassOrObject) declaration, getSettings()));
+ }
+ else if (getSettings().isShowMembers()) {
+ result.add(new KtDeclarationTreeNode(getProject(), declaration, getSettings()));
+ }
+ }
+ }
+
+ return result;
+ }
+}
diff --git a/idea/src/org/jetbrains/kotlin/idea/projectView/KtFileTreeNode.java.193 b/idea/src/org/jetbrains/kotlin/idea/projectView/KtFileTreeNode.java.193
new file mode 100644
index 0000000..23273f7
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/projectView/KtFileTreeNode.java.193
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2010-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 org.jetbrains.kotlin.idea.projectView;
+
+import com.intellij.ide.projectView.ViewSettings;
+import com.intellij.ide.projectView.impl.nodes.PsiFileNode;
+import com.intellij.ide.util.treeView.AbstractTreeNode;
+import com.intellij.openapi.project.Project;
+import org.jetbrains.kotlin.psi.KtClassOrObject;
+import org.jetbrains.kotlin.psi.KtDeclaration;
+import org.jetbrains.kotlin.psi.KtFile;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+public class KtFileTreeNode extends PsiFileNode {
+ public KtFileTreeNode(Project project, KtFile value, ViewSettings viewSettings) {
+ super(project, value, viewSettings);
+ }
+
+ public final KtFile getKtFile() {
+ return (KtFile) getValue();
+ }
+
+ @Override
+ public Collection<AbstractTreeNode> getChildrenImpl() {
+ KtFile file = (KtFile) getValue();
+
+ if (file == null) return Collections.emptyList();
+ ArrayList<AbstractTreeNode> result = new ArrayList<AbstractTreeNode>();
+
+ if (getSettings().isShowMembers()) {
+ @SuppressWarnings("ConstantConditions") List<KtDeclaration> declarations = (file.isScript() ? file.getScript() : file).getDeclarations();
+
+ for (KtDeclaration declaration : declarations) {
+ if (declaration instanceof KtClassOrObject) {
+ result.add(new KtClassOrObjectTreeNode(file.getProject(), (KtClassOrObject) declaration, getSettings()));
+ }
+ else if (getSettings().isShowMembers()) {
+ result.add(new KtDeclarationTreeNode(getProject(), declaration, getSettings()));
+ }
+ }
+ }
+
+ return result;
+ }
+}
diff --git a/idea/src/org/jetbrains/kotlin/idea/projectView/compat.kt b/idea/src/org/jetbrains/kotlin/idea/projectView/compat.kt
index d8037be..5c37059 100644
--- a/idea/src/org/jetbrains/kotlin/idea/projectView/compat.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/projectView/compat.kt
@@ -1,11 +1,11 @@
-/*
- * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
- * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
- */
-
-package org.jetbrains.kotlin.idea.projectView
-
-import com.intellij.ide.util.treeView.AbstractTreeNode
-
-// BUNCH: 193
-typealias AbstractTreeNodeAny = AbstractTreeNode<Any>
\ No newline at end of file
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.projectView
+
+import com.intellij.ide.util.treeView.AbstractTreeNode
+
+// BUNCH: 193
+typealias AbstractTreeNodeAny = AbstractTreeNode<*>
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/projectView/compat.kt.193 b/idea/src/org/jetbrains/kotlin/idea/projectView/compat.kt.193
new file mode 100644
index 0000000..2a6953f
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/projectView/compat.kt.193
@@ -0,0 +1,11 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.projectView
+
+import com.intellij.ide.util.treeView.AbstractTreeNode
+
+// BUNCH: 193
+typealias AbstractTreeNodeAny = AbstractTreeNode<Any>
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSignaturePresentationBuilder.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSignaturePresentationBuilder.kt
new file mode 100644
index 0000000..ff59b80
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSignaturePresentationBuilder.kt
@@ -0,0 +1,77 @@
+package org.jetbrains.kotlin.idea.refactoring.suggested
+
+import com.intellij.refactoring.suggested.SuggestedRefactoringSupport
+import com.intellij.refactoring.suggested.SignatureChangePresentationModel.Effect
+import com.intellij.refactoring.suggested.SignatureChangePresentationModel.TextFragment.Leaf
+import com.intellij.refactoring.suggested.SignaturePresentationBuilder
+
+internal class KotlinSignaturePresentationBuilder(
+ signature: SuggestedRefactoringSupport.Signature,
+ otherSignature: SuggestedRefactoringSupport.Signature,
+ isOldSignature: Boolean
+) : SignaturePresentationBuilder(signature, otherSignature, isOldSignature)
+{
+ override fun buildPresentation() {
+ val declarationType = (signature.additionalData as KotlinSignatureAdditionalData).declarationType
+ val keyword = declarationType.prefixKeyword
+ if (keyword != null) {
+ fragments += Leaf("$keyword ")
+ }
+
+ signature.receiverType?.let {
+ when (val effect = effect(it, otherSignature.receiverType)) {
+ Effect.Modified -> {
+ fragments += Leaf(it, effect)
+ fragments += Leaf(".")
+ }
+
+ else -> {
+ fragments += Leaf("$it.", effect)
+ }
+ }
+ }
+
+ val name = if (declarationType == DeclarationType.SECONDARY_CONSTRUCTOR) "constructor" else signature.name
+ fragments += Leaf(name, effect(signature.name, otherSignature.name))
+
+ if (declarationType.isFunction) {
+ buildParameterList { fragments, parameter, correspondingParameter ->
+ if (parameter.modifiers.isNotEmpty()) {
+ fragments += leaf(parameter.modifiers, correspondingParameter?.modifiers ?: parameter.modifiers)
+ fragments += Leaf(" ")
+ }
+
+ fragments += leaf(parameter.name, correspondingParameter?.name ?: parameter.name)
+
+ fragments += Leaf(": ")
+
+ fragments += leaf(parameter.type, correspondingParameter?.type ?: parameter.type)
+
+ val defaultValue = parameter.defaultValue
+ if (defaultValue != null) {
+ val defaultValueEffect = if (correspondingParameter != null)
+ effect(defaultValue, correspondingParameter.defaultValue)
+ else
+ Effect.None
+ fragments += Leaf(" = ", defaultValueEffect.takeIf { it != Effect.Modified } ?: Effect.None)
+ fragments += Leaf(defaultValue, defaultValueEffect)
+ }
+ }
+ } else {
+ require(signature.parameters.isEmpty())
+ }
+
+ signature.type?.let { type ->
+ when (val effect = effect(type, otherSignature.type)) {
+ Effect.Added, Effect.Removed, Effect.None -> {
+ fragments += Leaf(": ${signature.type}", effect)
+ }
+
+ Effect.Modified -> {
+ fragments += Leaf(": ")
+ fragments += Leaf(type, effect)
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSignaturePresentationBuilder.kt.193 b/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSignaturePresentationBuilder.kt.193
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSignaturePresentationBuilder.kt.193
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringAvailability.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringAvailability.kt
new file mode 100644
index 0000000..ce4a2bd
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringAvailability.kt
@@ -0,0 +1,162 @@
+package org.jetbrains.kotlin.idea.refactoring.suggested
+
+import com.intellij.psi.PsiNamedElement
+import com.intellij.refactoring.suggested.*
+import com.intellij.refactoring.suggested.SuggestedRefactoringSupport.Parameter
+import com.intellij.refactoring.suggested.SuggestedRefactoringSupport.Signature
+import org.jetbrains.kotlin.descriptors.CallableDescriptor
+import org.jetbrains.kotlin.idea.caches.project.forcedModuleInfo
+import org.jetbrains.kotlin.idea.caches.project.getModuleInfo
+import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
+import org.jetbrains.kotlin.idea.refactoring.isInterfaceClass
+import org.jetbrains.kotlin.lexer.KtTokens
+import org.jetbrains.kotlin.psi.KtCallableDeclaration
+import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
+import org.jetbrains.kotlin.psi.psiUtil.hasBody
+import org.jetbrains.kotlin.renderer.DescriptorRenderer
+import org.jetbrains.kotlin.types.KotlinType
+import org.jetbrains.kotlin.types.isError
+
+class KotlinSuggestedRefactoringAvailability(refactoringSupport: SuggestedRefactoringSupport) :
+ SuggestedRefactoringAvailability(refactoringSupport)
+{
+ override fun refineSignaturesWithResolve(state: SuggestedRefactoringState): SuggestedRefactoringState {
+ val newDeclaration = state.declaration as? KtCallableDeclaration ?: return state
+ val oldDeclaration = state.createRestoredDeclarationCopy(refactoringSupport) as? KtCallableDeclaration ?: return state
+ oldDeclaration.containingKtFile.forcedModuleInfo = newDeclaration.getModuleInfo()
+
+ val descriptorWithOldSignature = oldDeclaration.resolveToDescriptorIfAny() as CallableDescriptor
+ val descriptorWithNewSignature = newDeclaration.resolveToDescriptorIfAny() as CallableDescriptor
+
+ val oldSignature = state.oldSignature
+ val newSignature = state.newSignature
+
+ val (oldReturnType, newReturnType) = refineType(
+ oldSignature.type,
+ newSignature.type,
+ descriptorWithOldSignature.returnType,
+ descriptorWithNewSignature.returnType
+ )
+
+ val improvedOldParameterTypesById = mutableMapOf<Any, String>()
+ val improvedNewParameterTypesById = mutableMapOf<Any, String>()
+ for (oldParameter in oldSignature.parameters) {
+ val id = oldParameter.id
+ val newParameter = newSignature.parameterById(id) ?: continue
+ val oldIndex = oldSignature.parameterIndex(oldParameter)
+ val newIndex = newSignature.parameterIndex(newParameter)
+ val (oldType, newType) = refineType(
+ oldParameter.type,
+ newParameter.type,
+ descriptorWithOldSignature.valueParameters[oldIndex].type,
+ descriptorWithNewSignature.valueParameters[newIndex].type
+ )
+ // oldType and newType may not be null because arguments of refineType call were all non-null
+ improvedOldParameterTypesById[id] = oldType!!
+ improvedNewParameterTypesById[id] = newType!!
+ }
+ val oldParameters = oldSignature.parameters.map { it.copy(type = improvedOldParameterTypesById[it.id] ?: it.type) }
+ val newParameters = newSignature.parameters.map { it.copy(type = improvedNewParameterTypesById[it.id] ?: it.type) }
+
+ val oldAdditionalData = oldSignature.additionalData as KotlinSignatureAdditionalData?
+ val newAdditionalData = newSignature.additionalData as KotlinSignatureAdditionalData?
+ val (oldReceiverType, newReceiverType) = refineType(
+ oldAdditionalData?.receiverType,
+ newAdditionalData?.receiverType,
+ descriptorWithOldSignature.extensionReceiverParameter?.type,
+ descriptorWithNewSignature.extensionReceiverParameter?.type
+ )
+
+ return state.copy(
+ oldSignature = Signature.create(
+ oldSignature.name,
+ oldReturnType,
+ oldParameters,
+ oldAdditionalData?.copy(receiverType = oldReceiverType)
+ )!!,
+ newSignature = Signature.create(
+ newSignature.name,
+ newReturnType,
+ newParameters,
+ newAdditionalData?.copy(receiverType = newReceiverType)
+ )!!
+ )
+ }
+
+ private fun refineType(
+ oldTypeInCode: String?,
+ newTypeInCode: String?,
+ oldTypeResolved: KotlinType?,
+ newTypeResolved: KotlinType?
+ ): Pair<String?, String?> {
+ if (oldTypeResolved?.isError == true || newTypeResolved?.isError == true) {
+ return oldTypeInCode to newTypeInCode
+ }
+
+ val oldTypeFQ = oldTypeResolved?.fqText()
+ val newTypeFQ = newTypeResolved?.fqText()
+
+ if (oldTypeInCode != newTypeInCode) {
+ if (oldTypeFQ == newTypeFQ) {
+ return newTypeInCode to newTypeInCode
+ }
+ } else {
+ if (oldTypeFQ != newTypeFQ) {
+ return oldTypeFQ to newTypeFQ
+ }
+ }
+
+ return oldTypeInCode to newTypeInCode
+ }
+
+ private fun KotlinType.fqText() = DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(this)
+
+ override fun detectAvailableRefactoring(state: SuggestedRefactoringState): SuggestedRefactoringData? {
+ val declaration = state.declaration
+ if (declaration !is KtCallableDeclaration || KotlinSuggestedRefactoringSupport.isOnlyRenameSupported(declaration)) {
+ return SuggestedRenameData(declaration as PsiNamedElement, state.oldSignature.name)
+ }
+
+ val oldSignature = state.oldSignature
+ val newSignature = state.newSignature
+ val updateUsagesData = SuggestedChangeSignatureData.create(state, USAGES)
+
+ if (hasParameterAddedRemovedOrReordered(oldSignature, newSignature)) return updateUsagesData
+
+ // for non-virtual function we can add or remove receiver for usages but not change its type
+ if ((oldSignature.receiverType == null) != (newSignature.receiverType == null)) return updateUsagesData
+
+ val (nameChanges, renameData) = nameChanges(oldSignature, newSignature, declaration, declaration.valueParameters)
+
+ if (hasTypeChanges(oldSignature, newSignature)) {
+ return if (nameChanges > 0)
+ updateUsagesData
+ else
+ declaration.overridesName()?.let { updateUsagesData.copy(nameOfStuffToUpdate = it) }
+ }
+
+ return when {
+ renameData != null -> renameData
+ nameChanges > 0 -> updateUsagesData
+ else -> null
+ }
+ }
+
+ private fun KtCallableDeclaration.overridesName(): String? {
+ return when {
+ hasModifier(KtTokens.ABSTRACT_KEYWORD) -> IMPLEMENTATIONS
+ hasModifier(KtTokens.OPEN_KEYWORD) -> OVERRIDES
+ containingClassOrObject?.isInterfaceClass() == true -> if (hasBody()) OVERRIDES else IMPLEMENTATIONS
+ hasModifier(KtTokens.EXPECT_KEYWORD) -> "actual declarations"
+ else -> null
+ }
+ }
+
+ override fun hasTypeChanges(oldSignature: Signature, newSignature: Signature): Boolean {
+ return super.hasTypeChanges(oldSignature, newSignature) || oldSignature.receiverType != newSignature.receiverType
+ }
+
+ override fun hasParameterTypeChanges(oldParam: Parameter, newParam: Parameter): Boolean {
+ return super.hasParameterTypeChanges(oldParam, newParam) || oldParam.modifiers != newParam.modifiers
+ }
+}
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringAvailability.kt.193 b/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringAvailability.kt.193
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringAvailability.kt.193
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringExecution.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringExecution.kt
new file mode 100644
index 0000000..11e50fc
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringExecution.kt
@@ -0,0 +1,160 @@
+package org.jetbrains.kotlin.idea.refactoring.suggested
+
+import com.intellij.psi.PsiElement
+import com.intellij.refactoring.suggested.SuggestedChangeSignatureData
+import com.intellij.refactoring.suggested.SuggestedRefactoringExecution
+import org.jetbrains.kotlin.descriptors.CallableDescriptor
+import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
+import org.jetbrains.kotlin.idea.refactoring.changeSignature.*
+import org.jetbrains.kotlin.psi.KtCallableDeclaration
+import org.jetbrains.kotlin.psi.KtDeclaration
+import org.jetbrains.kotlin.psi.KtExpression
+import org.jetbrains.kotlin.psi.KtPsiFactory
+import org.jetbrains.kotlin.types.isError
+import org.jetbrains.kotlin.utils.addIfNotNull
+
+class KotlinSuggestedRefactoringExecution(
+ refactoringSupport: KotlinSuggestedRefactoringSupport
+) : SuggestedRefactoringExecution(refactoringSupport) {
+
+ private data class PrepareChangeSignatureResult(
+ val returnTypeInfo: KotlinTypeInfo,
+ val parameterTypeInfos: List<KotlinTypeInfo>
+ )
+
+ override fun prepareChangeSignature(data: SuggestedChangeSignatureData): Any {
+ val declaration = data.declaration as KtCallableDeclaration
+ val descriptorWithNewSignature = declaration.resolveToDescriptorIfAny() as CallableDescriptor
+ val newSignature = data.newSignature
+
+ val returnType = descriptorWithNewSignature.returnType
+ val returnTypeInfo = if (returnType != null && !returnType.isError) {
+ KotlinTypeInfo(type = returnType, isCovariant = true)
+ } else {
+ KotlinTypeInfo(text = newSignature.type, isCovariant = true)
+ }
+
+ require(descriptorWithNewSignature.valueParameters.size == newSignature.parameters.size) {
+ "Number of parameters of newSignature is ${newSignature.parameters.size} and of the descriptor is ${descriptorWithNewSignature.valueParameters.size}"
+ }
+
+ val parameterTypeInfos = descriptorWithNewSignature.valueParameters.zip(newSignature.parameters)
+ .map { (parameterDescriptor, parameterData) ->
+ val type = parameterDescriptor.varargElementType ?: parameterDescriptor.type
+ if (!type.isError) {
+ KotlinTypeInfo(type = type, isCovariant = true)
+ } else {
+ KotlinTypeInfo(text = parameterData.type, isCovariant = true)
+ }
+ }
+
+ return PrepareChangeSignatureResult(returnTypeInfo, parameterTypeInfos)
+ }
+
+ override fun performChangeSignature(
+ data: SuggestedChangeSignatureData,
+ newParameterValues: List<NewParameterValue>,
+ preparedData: Any?
+ ) {
+ val (returnTypeInfo, parameterTypeInfos) = preparedData as PrepareChangeSignatureResult
+
+ val declaration = data.declaration as KtDeclaration
+ val descriptor = declaration.resolveToDescriptorIfAny() as CallableDescriptor
+ val project = declaration.project
+
+ val configuration = object : KotlinChangeSignatureConfiguration {
+ override fun performSilently(affectedFunctions: Collection<PsiElement>) = true
+ }
+ val changeSignature = KotlinChangeSignature(project, descriptor, configuration, declaration, null)
+ val methodDescriptor = changeSignature.adjustDescriptor(listOf(descriptor))!!
+
+ val parameters = mutableListOf<KotlinParameterInfo>()
+ var newParameterValueIndex = 0
+
+ val receiver: KotlinParameterInfo? = if (data.newSignature.receiverType != null) {
+ val newTypeInfo = KotlinTypeInfo(text = data.newSignature.receiverType, isCovariant = false)
+ if (data.oldSignature.receiverType != null) {
+ methodDescriptor.receiver!!.apply { currentTypeInfo = newTypeInfo }
+ } else {
+ KotlinParameterInfo(descriptor, -1, "", newTypeInfo)
+ .withDefaultValue(newParameterValues[newParameterValueIndex++])
+ }
+ } else {
+ null
+ }
+
+ parameters.addIfNotNull(receiver)
+
+ val psiFactory = KtPsiFactory(project)
+
+ for ((index, parameter) in data.newSignature.parameters.withIndex()) {
+ val initialIndex = data.oldSignature.parameterById(parameter.id)
+ ?.let { data.oldSignature.parameterIndex(it) }
+
+ val defaultValue = parameter.defaultValue?.let { psiFactory.createExpression(it) }
+
+ val modifierList = parameter.modifiers
+ .takeIf { it.isNotEmpty() }
+ ?.let { psiFactory.createModifierList(it) }
+
+ val parameterInfo = if (initialIndex == null) {
+ KotlinParameterInfo(
+ descriptor,
+ -1,
+ parameter.name,
+ parameterTypeInfos[index],
+ defaultValueForParameter = defaultValue,
+ modifierList = modifierList
+ ).withDefaultValue(newParameterValues[newParameterValueIndex++])
+ } else {
+ KotlinParameterInfo(
+ descriptor,
+ initialIndex,
+ parameter.name,
+ methodDescriptor.parameters[initialIndex].originalTypeInfo,
+ defaultValueForParameter = defaultValue,
+ modifierList = modifierList
+ ).apply {
+ currentTypeInfo = parameterTypeInfos[index]
+ }
+ }
+ parameters.add(parameterInfo)
+ }
+
+ val changeInfo = KotlinChangeInfo(
+ methodDescriptor,
+ context = declaration,
+ name = data.newSignature.name,
+ newReturnTypeInfo = returnTypeInfo,
+ parameterInfos = parameters,
+ receiver = receiver
+ )
+ val processor = KotlinChangeSignatureProcessor(project, changeInfo, "")
+ processor.run()
+ }
+
+ //TODO: we can't just set defaultValueForCall due to bug in KotlinParameterInfo
+ private fun KotlinParameterInfo.withDefaultValue(value: NewParameterValue): KotlinParameterInfo {
+ when (value) {
+ is NewParameterValue.AnyVariable -> {
+ isUseAnySingleVariable = true
+ return this
+ }
+
+ is NewParameterValue.Expression -> {
+ val defaultValueForCall = value.expression as KtExpression
+ return KotlinParameterInfo(
+ callableDescriptor, originalIndex, name, originalTypeInfo,
+ defaultValueForParameter, defaultValueForCall, valOrVar, modifierList
+ ).apply {
+ currentTypeInfo = this@withDefaultValue.currentTypeInfo
+ }
+ }
+
+ is NewParameterValue.None -> {
+ defaultValueForCall = null
+ return this
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringExecution.kt.193 b/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringExecution.kt.193
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringExecution.kt.193
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringStateChanges.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringStateChanges.kt
new file mode 100644
index 0000000..d94d733
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringStateChanges.kt
@@ -0,0 +1,66 @@
+package org.jetbrains.kotlin.idea.refactoring.suggested
+
+import com.intellij.openapi.util.TextRange
+import com.intellij.psi.PsiElement
+import com.intellij.refactoring.suggested.SuggestedRefactoringState
+import com.intellij.refactoring.suggested.SuggestedRefactoringStateChanges
+import com.intellij.refactoring.suggested.SuggestedRefactoringSupport
+import com.intellij.refactoring.suggested.SuggestedRefactoringSupport.Parameter
+import com.intellij.refactoring.suggested.SuggestedRefactoringSupport.Signature
+import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
+import org.jetbrains.kotlin.lexer.KtTokens
+import org.jetbrains.kotlin.psi.KtCallableDeclaration
+import org.jetbrains.kotlin.psi.KtDeclaration
+import org.jetbrains.kotlin.psi.KtFunction
+import org.jetbrains.kotlin.psi.KtParameter
+import org.jetbrains.kotlin.psi.psiUtil.children
+
+class KotlinSuggestedRefactoringStateChanges(refactoringSupport: SuggestedRefactoringSupport) :
+ SuggestedRefactoringStateChanges(refactoringSupport)
+{
+ override fun createInitialState(declaration: PsiElement): SuggestedRefactoringState? {
+ declaration as KtDeclaration
+ if (declaration.hasModifier(KtTokens.OVERRIDE_KEYWORD)) return null // currently not supported
+ if (declaration.hasModifier(KtTokens.ACTUAL_KEYWORD)) return null // currently not supported
+ return super.createInitialState(declaration)
+ }
+
+ override fun signature(declaration: PsiElement, prevState: SuggestedRefactoringState?): Signature? {
+ declaration as KtDeclaration
+ val name = declaration.name ?: return null
+ if (declaration !is KtCallableDeclaration || KotlinSuggestedRefactoringSupport.isOnlyRenameSupported(declaration)) {
+ return Signature.create(name, null, emptyList(), null)
+ }
+
+ val parameters = declaration.valueParameters.map { it.extractParameterData() ?: return null }
+ val type = declaration.typeReference?.text
+ val receiverType = declaration.receiverTypeReference?.text
+ val signature = Signature.create(
+ name,
+ type,
+ parameters,
+ KotlinSignatureAdditionalData(DeclarationType.fromDeclaration(declaration), receiverType)
+ ) ?: return null
+
+ return if (prevState == null) signature else matchParametersWithPrevState(signature, declaration, prevState)
+ }
+
+ override fun parameterMarkerRanges(declaration: PsiElement): List<TextRange?> {
+ if (declaration !is KtFunction) return emptyList()
+ return declaration.valueParameters.map { it.colon?.textRange }
+ }
+
+ private fun KtParameter.extractParameterData(): Parameter? {
+ val modifiers = modifierList?.node?.children()
+ ?.filter { it.elementType is KtModifierKeywordToken && it.text in modifiersToInclude }
+ ?.joinToString(separator = " ") { it.text } ?: ""
+ return Parameter(
+ Any(),
+ name ?: return null,
+ typeReference?.text ?: return null,
+ KotlinParameterAdditionalData(defaultValue?.text/*TODO: strip comments etc*/, modifiers)
+ )
+ }
+
+ private val modifiersToInclude = setOf(KtTokens.VARARG_KEYWORD.value)
+}
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringStateChanges.kt.193 b/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringStateChanges.kt.193
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringStateChanges.kt.193
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringSupport.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringSupport.kt
new file mode 100644
index 0000000..efaa95f
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringSupport.kt
@@ -0,0 +1,153 @@
+package org.jetbrains.kotlin.idea.refactoring.suggested
+
+import com.intellij.openapi.util.TextRange
+import com.intellij.psi.PsiElement
+import com.intellij.psi.PsiFile
+import com.intellij.refactoring.suggested.SuggestedRefactoringSupport
+import com.intellij.refactoring.suggested.SuggestedRefactoringSupport.Parameter
+import com.intellij.refactoring.suggested.SuggestedRefactoringSupport.Signature
+import org.jetbrains.kotlin.psi.*
+import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
+
+class KotlinSuggestedRefactoringSupport : SuggestedRefactoringSupport {
+ override fun isDeclaration(psiElement: PsiElement): Boolean {
+ if (psiElement !is KtDeclaration) return false
+ if (psiElement is KtParameter && psiElement.ownerFunction != null) return false
+ return true
+ }
+
+ override fun signatureRange(declaration: PsiElement): TextRange? {
+ when (declaration) {
+ is KtPrimaryConstructor -> return declaration.textRange
+
+ is KtSecondaryConstructor -> return declaration.valueParameterList?.textRange
+
+ is KtCallableDeclaration -> {
+ if (isOnlyRenameSupported(declaration)) {
+ return declaration.nameIdentifier?.textRange
+ }
+
+ val start = declaration.receiverTypeReference?.textRange?.startOffset
+ ?: declaration.nameIdentifier?.textRange?.startOffset
+ ?: return null
+ val end = (declaration.typeReference ?: declaration.valueParameterList ?: declaration.nameIdentifier)
+ ?.textRange?.endOffset
+ ?: return null
+ return TextRange(start, end)
+ }
+
+ is KtNamedDeclaration -> return declaration.nameIdentifier?.textRange
+
+ else -> return null
+ }
+ }
+
+ override fun importsRange(psiFile: PsiFile): TextRange? {
+ return (psiFile as KtFile).importList?.textRange
+ }
+
+ override fun nameRange(declaration: PsiElement): TextRange? {
+ val identifier = when (declaration) {
+ is KtPrimaryConstructor -> declaration.containingClassOrObject?.nameIdentifier
+ is KtSecondaryConstructor -> declaration.getConstructorKeyword()
+ is KtNamedDeclaration -> declaration.nameIdentifier
+ else -> null
+ }
+ return identifier?.textRange
+ }
+
+ override fun hasSyntaxError(declaration: PsiElement): Boolean {
+ if (super.hasSyntaxError(declaration)) return true
+
+ // do not suggest renaming of local variable which has neither type nor initializer
+ // it's important because such variable declarations may appear on typing "val name = " before an expression
+ if (declaration is KtProperty && declaration.isLocal) {
+ if (declaration.typeReference == null && declaration.initializer == null) return true
+ }
+
+ return false
+ }
+
+ override fun isIdentifierStart(c: Char) = c.isJavaIdentifierStart()
+ override fun isIdentifierPart(c: Char) = c.isJavaIdentifierPart()
+
+ override val stateChanges = KotlinSuggestedRefactoringStateChanges(this)
+ override val availability = KotlinSuggestedRefactoringAvailability(this)
+ override val ui get() = KotlinSuggestedRefactoringUI
+ override val execution = KotlinSuggestedRefactoringExecution(this)
+
+ companion object {
+ fun isOnlyRenameSupported(declaration: KtCallableDeclaration): Boolean {
+ // for local variable - only rename
+ return declaration is KtVariableDeclaration && KtPsiUtil.isLocal(declaration)
+ }
+ }
+}
+
+enum class DeclarationType {
+ FUN {
+ override val prefixKeyword get() = "fun"
+ override val isFunction get() = true
+ },
+ VAL {
+ override val prefixKeyword get() = "val"
+ override val isFunction get() = false
+ },
+ VAR {
+ override val prefixKeyword get() = "var"
+ override val isFunction get() = false
+ },
+ PRIMARY_CONSTRUCTOR {
+ override val prefixKeyword: String?
+ get() = null
+ override val isFunction get() = true
+ },
+ SECONDARY_CONSTRUCTOR {
+ override val prefixKeyword: String?
+ get() = null
+ override val isFunction get() = true
+ },
+ OTHER {
+ override val prefixKeyword: String?
+ get() = null
+ override val isFunction get() = false
+ }
+
+ ;
+
+ abstract val prefixKeyword: String?
+ abstract val isFunction: Boolean
+
+ companion object {
+ fun fromDeclaration(declaration: KtDeclaration): DeclarationType = when (declaration) {
+ is KtPrimaryConstructor -> PRIMARY_CONSTRUCTOR
+
+ is KtSecondaryConstructor -> SECONDARY_CONSTRUCTOR
+
+ is KtNamedFunction -> FUN
+
+ is KtProperty -> if (declaration.isVar) VAR else VAL
+
+ else -> OTHER
+ }
+ }
+}
+
+internal data class KotlinSignatureAdditionalData(
+ val declarationType: DeclarationType,
+ val receiverType: String?
+) : SuggestedRefactoringSupport.SignatureAdditionalData
+
+internal data class KotlinParameterAdditionalData(
+ val defaultValue: String?,
+ val modifiers: String
+) : SuggestedRefactoringSupport.ParameterAdditionalData
+
+internal val Signature.receiverType: String?
+ get() = (additionalData as KotlinSignatureAdditionalData?)?.receiverType
+
+internal val Parameter.defaultValue: String?
+ get() = (additionalData as KotlinParameterAdditionalData?)?.defaultValue
+
+internal val Parameter.modifiers: String
+ get() = (additionalData as KotlinParameterAdditionalData?)?.modifiers ?: ""
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringSupport.kt.193 b/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringSupport.kt.193
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringSupport.kt.193
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringUI.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringUI.kt
new file mode 100644
index 0000000..7c6efd4
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringUI.kt
@@ -0,0 +1,46 @@
+package org.jetbrains.kotlin.idea.refactoring.suggested
+
+import com.intellij.psi.PsiCodeFragment
+import com.intellij.refactoring.suggested.SuggestedChangeSignatureData
+import com.intellij.refactoring.suggested.SuggestedRefactoringExecution.NewParameterValue
+import com.intellij.refactoring.suggested.SuggestedRefactoringSupport.Signature
+import com.intellij.refactoring.suggested.SuggestedRefactoringUI
+import com.intellij.refactoring.suggested.SignaturePresentationBuilder
+import org.jetbrains.kotlin.psi.KtExpressionCodeFragment
+import org.jetbrains.kotlin.psi.KtPsiFactory
+
+object KotlinSuggestedRefactoringUI : SuggestedRefactoringUI() {
+ override fun createSignaturePresentationBuilder(
+ signature: Signature,
+ otherSignature: Signature,
+ isOldSignature: Boolean
+ ): SignaturePresentationBuilder {
+ return KotlinSignaturePresentationBuilder(signature, otherSignature, isOldSignature)
+ }
+
+ override fun extractNewParameterData(data: SuggestedChangeSignatureData): List<NewParameterData> {
+ val newParameters = mutableListOf<NewParameterData>()
+
+ val declaration = data.declaration
+ val factory = KtPsiFactory(declaration.project)
+
+ fun createCodeFragment() = factory.createExpressionCodeFragment("", declaration)
+
+ if (data.newSignature.receiverType != null && data.oldSignature.receiverType == null) {
+ newParameters.add(NewParameterData("<receiver>", createCodeFragment(), false/*TODO*/))
+ }
+
+ for (parameter in data.newSignature.parameters) {
+ if (data.oldSignature.parameterById(parameter.id) == null) {
+ newParameters.add(NewParameterData(parameter.name, createCodeFragment(), false/*TODO*/))
+ }
+ }
+
+ return newParameters
+ }
+
+ override fun extractValue(fragment: PsiCodeFragment): NewParameterValue.Expression? {
+ return (fragment as KtExpressionCodeFragment).getContentElement()
+ ?.let { NewParameterValue.Expression(it) }
+ }
+}
diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringUI.kt.193 b/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringUI.kt.193
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringUI.kt.193
diff --git a/idea/src/org/jetbrains/kotlin/idea/slicer/KotlinUsageContextDataFlowPanelBase.kt b/idea/src/org/jetbrains/kotlin/idea/slicer/KotlinUsageContextDataFlowPanelBase.kt
index 69815f8..0b28de6 100644
--- a/idea/src/org/jetbrains/kotlin/idea/slicer/KotlinUsageContextDataFlowPanelBase.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/slicer/KotlinUsageContextDataFlowPanelBase.kt
@@ -1,127 +1,127 @@
-/*
- * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
- * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
- */
-
-package org.jetbrains.kotlin.idea.slicer
-
-import com.intellij.analysis.AnalysisScope
-import com.intellij.openapi.Disposable
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.util.Disposer
-import com.intellij.openapi.wm.ToolWindowId
-import com.intellij.openapi.wm.ToolWindowManager
-import com.intellij.psi.PsiElement
-import com.intellij.slicer.DuplicateMap
-import com.intellij.slicer.SliceAnalysisParams
-import com.intellij.slicer.SlicePanel
-import com.intellij.slicer.SliceRootNode
-import com.intellij.usageView.UsageInfo
-import com.intellij.usageView.UsageViewBundle
-import com.intellij.usages.PsiElementUsageTarget
-import com.intellij.usages.UsageContextPanel
-import com.intellij.usages.UsageView
-import com.intellij.usages.UsageViewPresentation
-import com.intellij.usages.impl.UsageContextPanelBase
-import com.intellij.usages.impl.UsageViewImpl
-import org.jetbrains.kotlin.psi.KtDeclaration
-import java.awt.BorderLayout
-import javax.swing.JLabel
-import javax.swing.JPanel
-import javax.swing.SwingConstants
-
-sealed class KotlinUsageContextDataFlowPanelBase(
- project: Project,
- presentation: UsageViewPresentation,
- private val isInflow: Boolean
-) : UsageContextPanelBase(project, presentation) {
- private var panel: JPanel? = null
-
- abstract class ProviderBase : UsageContextPanel.Provider {
- override fun isAvailableFor(usageView: UsageView): Boolean {
- val target = (usageView as UsageViewImpl).targets.firstOrNull() ?: return false
- val element = (target as? PsiElementUsageTarget)?.element
- return element is KtDeclaration && element.isValid
- }
- }
-
- private fun createParams(element: PsiElement): SliceAnalysisParams {
- return SliceAnalysisParams().apply {
- scope = AnalysisScope(element.project)
- dataFlowToThis = isInflow
- showInstanceDereferences = true
- }
- }
-
- protected fun createPanel(element: PsiElement, dataFlowToThis: Boolean): JPanel {
- val toolWindow = ToolWindowManager.getInstance(myProject).getToolWindow(ToolWindowId.FIND)
- val params = createParams(element)
-
- val rootNode = SliceRootNode(myProject, DuplicateMap(), KotlinSliceUsage(element, params))
-
- return object : SlicePanel(myProject, dataFlowToThis, rootNode, false, toolWindow) {
- override fun isToShowAutoScrollButton() = false
-
- override fun isToShowPreviewButton() = false
-
- override fun isAutoScroll() = false
-
- override fun setAutoScroll(autoScroll: Boolean) {}
-
- override fun isPreview() = false
-
- override fun setPreview(preview: Boolean) {}
- }
- }
-
- public override fun updateLayoutLater(infos: List<UsageInfo>?) {
- if (infos == null) {
- removeAll()
- val title = UsageViewBundle.message("select.the.usage.to.preview", myPresentation.usagesWord)
- add(JLabel(title, SwingConstants.CENTER), BorderLayout.CENTER)
- } else {
- val element = infos.firstOrNull()?.element ?: return
- if (panel != null) {
- Disposer.dispose(panel as Disposable)
- }
-
- val panel = createPanel(element, isInflow)
- Disposer.register(this, panel as Disposable)
- removeAll()
- add(panel, BorderLayout.CENTER)
- this.panel = panel
- }
- revalidate()
- }
-
- override fun dispose() {
- super.dispose()
- panel = null
- }
-}
-
-class KotlinUsageContextDataInflowPanel(
- project: Project,
- presentation: UsageViewPresentation
-) : KotlinUsageContextDataFlowPanelBase(project, presentation, true) {
- class Provider : ProviderBase() {
- override fun create(usageView: UsageView): UsageContextPanel {
- return KotlinUsageContextDataInflowPanel((usageView as UsageViewImpl).project, usageView.getPresentation())
- }
-
- override fun getTabTitle() = "Dataflow to Here"
- }
-}
-
-class KotlinUsageContextDataOutflowPanel(
- project: Project,
- presentation: UsageViewPresentation
-) : KotlinUsageContextDataFlowPanelBase(project, presentation, false) {
- class Provider : ProviderBase() {
- override fun create(usageView: UsageView): UsageContextPanel {
- return KotlinUsageContextDataOutflowPanel((usageView as UsageViewImpl).project, usageView.getPresentation())
- }
-
- override fun getTabTitle() = "Dataflow from Here"
- }
+/*
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.slicer
+
+import com.intellij.analysis.AnalysisScope
+import com.intellij.openapi.Disposable
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.util.Disposer
+import com.intellij.openapi.wm.ToolWindowId
+import com.intellij.openapi.wm.ToolWindowManager
+import com.intellij.psi.PsiElement
+import com.intellij.slicer.DuplicateMap
+import com.intellij.slicer.SliceAnalysisParams
+import com.intellij.slicer.SlicePanel
+import com.intellij.slicer.SliceRootNode
+import com.intellij.usageView.UsageInfo
+import com.intellij.usageView.UsageViewBundle
+import com.intellij.usages.PsiElementUsageTarget
+import com.intellij.usages.UsageContextPanel
+import com.intellij.usages.UsageView
+import com.intellij.usages.UsageViewPresentation
+import com.intellij.usages.impl.UsageContextPanelBase
+import com.intellij.usages.impl.UsageViewImpl
+import org.jetbrains.kotlin.psi.KtDeclaration
+import java.awt.BorderLayout
+import javax.swing.JLabel
+import javax.swing.JPanel
+import javax.swing.SwingConstants
+
+sealed class KotlinUsageContextDataFlowPanelBase(
+ project: Project,
+ presentation: UsageViewPresentation,
+ private val isInflow: Boolean
+) : UsageContextPanelBase(project, presentation) {
+ private var panel: JPanel? = null
+
+ abstract class ProviderBase : UsageContextPanel.Provider {
+ override fun isAvailableFor(usageView: UsageView): Boolean {
+ val target = (usageView as UsageViewImpl).targets.firstOrNull() ?: return false
+ val element = (target as? PsiElementUsageTarget)?.element
+ return element is KtDeclaration && element.isValid
+ }
+ }
+
+ private fun createParams(element: PsiElement): SliceAnalysisParams {
+ return SliceAnalysisParams().apply {
+ scope = AnalysisScope(element.project)
+ dataFlowToThis = isInflow
+ showInstanceDereferences = true
+ }
+ }
+
+ protected fun createPanel(element: PsiElement, dataFlowToThis: Boolean): JPanel {
+ val toolWindow = ToolWindowManager.getInstance(myProject).getToolWindow(ToolWindowId.FIND) ?: error("Can't find ToolWindowId.FIND")
+ val params = createParams(element)
+
+ val rootNode = SliceRootNode(myProject, DuplicateMap(), KotlinSliceUsage(element, params))
+
+ return object : SlicePanel(myProject, dataFlowToThis, rootNode, false, toolWindow) {
+ override fun isToShowAutoScrollButton() = false
+
+ override fun isToShowPreviewButton() = false
+
+ override fun isAutoScroll() = false
+
+ override fun setAutoScroll(autoScroll: Boolean) {}
+
+ override fun isPreview() = false
+
+ override fun setPreview(preview: Boolean) {}
+ }
+ }
+
+ public override fun updateLayoutLater(infos: List<UsageInfo>?) {
+ if (infos == null) {
+ removeAll()
+ val title = UsageViewBundle.message("select.the.usage.to.preview", myPresentation.usagesWord)
+ add(JLabel(title, SwingConstants.CENTER), BorderLayout.CENTER)
+ } else {
+ val element = infos.firstOrNull()?.element ?: return
+ if (panel != null) {
+ Disposer.dispose(panel as Disposable)
+ }
+
+ val panel = createPanel(element, isInflow)
+ Disposer.register(this, panel as Disposable)
+ removeAll()
+ add(panel, BorderLayout.CENTER)
+ this.panel = panel
+ }
+ revalidate()
+ }
+
+ override fun dispose() {
+ super.dispose()
+ panel = null
+ }
+}
+
+class KotlinUsageContextDataInflowPanel(
+ project: Project,
+ presentation: UsageViewPresentation
+) : KotlinUsageContextDataFlowPanelBase(project, presentation, true) {
+ class Provider : ProviderBase() {
+ override fun create(usageView: UsageView): UsageContextPanel {
+ return KotlinUsageContextDataInflowPanel((usageView as UsageViewImpl).project, usageView.getPresentation())
+ }
+
+ override fun getTabTitle() = "Dataflow to Here"
+ }
+}
+
+class KotlinUsageContextDataOutflowPanel(
+ project: Project,
+ presentation: UsageViewPresentation
+) : KotlinUsageContextDataFlowPanelBase(project, presentation, false) {
+ class Provider : ProviderBase() {
+ override fun create(usageView: UsageView): UsageContextPanel {
+ return KotlinUsageContextDataOutflowPanel((usageView as UsageViewImpl).project, usageView.getPresentation())
+ }
+
+ override fun getTabTitle() = "Dataflow from Here"
+ }
}
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/slicer/KotlinUsageContextDataFlowPanelBase.kt.193 b/idea/src/org/jetbrains/kotlin/idea/slicer/KotlinUsageContextDataFlowPanelBase.kt.193
new file mode 100644
index 0000000..8fa7360
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/slicer/KotlinUsageContextDataFlowPanelBase.kt.193
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.slicer
+
+import com.intellij.analysis.AnalysisScope
+import com.intellij.openapi.Disposable
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.util.Disposer
+import com.intellij.openapi.wm.ToolWindowId
+import com.intellij.openapi.wm.ToolWindowManager
+import com.intellij.psi.PsiElement
+import com.intellij.slicer.DuplicateMap
+import com.intellij.slicer.SliceAnalysisParams
+import com.intellij.slicer.SlicePanel
+import com.intellij.slicer.SliceRootNode
+import com.intellij.usageView.UsageInfo
+import com.intellij.usageView.UsageViewBundle
+import com.intellij.usages.PsiElementUsageTarget
+import com.intellij.usages.UsageContextPanel
+import com.intellij.usages.UsageView
+import com.intellij.usages.UsageViewPresentation
+import com.intellij.usages.impl.UsageContextPanelBase
+import com.intellij.usages.impl.UsageViewImpl
+import org.jetbrains.kotlin.psi.KtDeclaration
+import java.awt.BorderLayout
+import javax.swing.JLabel
+import javax.swing.JPanel
+import javax.swing.SwingConstants
+
+sealed class KotlinUsageContextDataFlowPanelBase(
+ project: Project,
+ presentation: UsageViewPresentation,
+ private val isInflow: Boolean
+) : UsageContextPanelBase(project, presentation) {
+ private var panel: JPanel? = null
+
+ abstract class ProviderBase : UsageContextPanel.Provider {
+ override fun isAvailableFor(usageView: UsageView): Boolean {
+ val target = (usageView as UsageViewImpl).targets.firstOrNull() ?: return false
+ val element = (target as? PsiElementUsageTarget)?.element
+ return element is KtDeclaration && element.isValid
+ }
+ }
+
+ private fun createParams(element: PsiElement): SliceAnalysisParams {
+ return SliceAnalysisParams().apply {
+ scope = AnalysisScope(element.project)
+ dataFlowToThis = isInflow
+ showInstanceDereferences = true
+ }
+ }
+
+ protected fun createPanel(element: PsiElement, dataFlowToThis: Boolean): JPanel {
+ val toolWindow = ToolWindowManager.getInstance(myProject).getToolWindow(ToolWindowId.FIND)
+ val params = createParams(element)
+
+ val rootNode = SliceRootNode(myProject, DuplicateMap(), KotlinSliceUsage(element, params))
+
+ return object : SlicePanel(myProject, dataFlowToThis, rootNode, false, toolWindow) {
+ override fun isToShowAutoScrollButton() = false
+
+ override fun isToShowPreviewButton() = false
+
+ override fun isAutoScroll() = false
+
+ override fun setAutoScroll(autoScroll: Boolean) {}
+
+ override fun isPreview() = false
+
+ override fun setPreview(preview: Boolean) {}
+ }
+ }
+
+ public override fun updateLayoutLater(infos: List<UsageInfo>?) {
+ if (infos == null) {
+ removeAll()
+ val title = UsageViewBundle.message("select.the.usage.to.preview", myPresentation.usagesWord)
+ add(JLabel(title, SwingConstants.CENTER), BorderLayout.CENTER)
+ } else {
+ val element = infos.firstOrNull()?.element ?: return
+ if (panel != null) {
+ Disposer.dispose(panel as Disposable)
+ }
+
+ val panel = createPanel(element, isInflow)
+ Disposer.register(this, panel as Disposable)
+ removeAll()
+ add(panel, BorderLayout.CENTER)
+ this.panel = panel
+ }
+ revalidate()
+ }
+
+ override fun dispose() {
+ super.dispose()
+ panel = null
+ }
+}
+
+class KotlinUsageContextDataInflowPanel(
+ project: Project,
+ presentation: UsageViewPresentation
+) : KotlinUsageContextDataFlowPanelBase(project, presentation, true) {
+ class Provider : ProviderBase() {
+ override fun create(usageView: UsageView): UsageContextPanel {
+ return KotlinUsageContextDataInflowPanel((usageView as UsageViewImpl).project, usageView.getPresentation())
+ }
+
+ override fun getTabTitle() = "Dataflow to Here"
+ }
+}
+
+class KotlinUsageContextDataOutflowPanel(
+ project: Project,
+ presentation: UsageViewPresentation
+) : KotlinUsageContextDataFlowPanelBase(project, presentation, false) {
+ class Provider : ProviderBase() {
+ override fun create(usageView: UsageView): UsageContextPanel {
+ return KotlinUsageContextDataOutflowPanel((usageView as UsageViewImpl).project, usageView.getPresentation())
+ }
+
+ override fun getTabTitle() = "Dataflow from Here"
+ }
+}
\ No newline at end of file
diff --git a/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/PsiElementChecker.kt b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/PsiElementChecker.kt
index 26fe638..a698bf8 100644
--- a/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/PsiElementChecker.kt
+++ b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/PsiElementChecker.kt
@@ -1,119 +1,120 @@
-/*
- * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
- * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
- */
-
-package org.jetbrains.kotlin.idea.caches.resolve
-
-import com.intellij.openapi.util.Key
-import com.intellij.psi.*
-import org.jetbrains.kotlin.asJava.elements.KtLightElement
-import org.jetbrains.kotlin.asJava.elements.KtLightModifierList
-import org.jetbrains.kotlin.idea.KotlinLanguage
-import org.junit.Assert
-
-object PsiElementChecker {
- val TEST_DATA_KEY = Key.create<Int>("Test Key")
-
- fun checkPsiElementStructure(lightClass: PsiClass) {
- checkPsiElement(lightClass)
-
- lightClass.methods.forEach {
- it.parameterList.parameters.forEach { checkPsiElement(it) }
- checkPsiElement(it)
- }
-
- lightClass.fields.forEach { checkPsiElement(it) }
-
- lightClass.innerClasses.forEach { checkPsiElementStructure(it) }
- }
-
- private fun checkPsiElement(element: PsiElement) {
- if (element !is KtLightElement<*, *> && element !is KtLightModifierList<*>) return
-
- if (element is PsiModifierListOwner) {
- val modifierList = element.modifierList
- if (modifierList != null) {
- checkPsiElement(modifierList)
- }
- }
-
- if (element is PsiTypeParameterListOwner) {
- val typeParameterList = element.typeParameterList
- if (typeParameterList != null) {
- checkPsiElement(typeParameterList)
- typeParameterList.typeParameters.forEach { checkPsiElement(it) }
- }
- }
-
- with(element) {
- try {
- Assert.assertEquals("Number of methods has changed. Please update test.", 55, PsiElement::class.java.methods.size)
-
- project
- Assert.assertTrue(language == KotlinLanguage.INSTANCE)
- manager
- children
- parent
- firstChild
- lastChild
- nextSibling
- prevSibling
- containingFile
- textRange
- //textRangeInParent - throws an exception for non-physical elements, it is expected behaviour
- startOffsetInParent
- textLength
- findElementAt(0)
- findReferenceAt(0)
- textOffset
- text
- textToCharArray()
- navigationElement
- originalElement
- textMatches("")
- Assert.assertTrue(textMatches(this))
- textContains('a')
- accept(PsiElementVisitor.EMPTY_VISITOR)
- acceptChildren(PsiElementVisitor.EMPTY_VISITOR)
-
- val copy = copy()
- Assert.assertTrue(copy == null || copy::class.java == this::class.java)
-
- // Modify methods:
- // add(this)
- // addBefore(this, lastChild)
- // addAfter(firstChild, this)
- // checkAdd(this)
- // addRange(firstChild, lastChild)
- // addRangeBefore(firstChild, lastChild, lastChild)
- // addRangeAfter(firstChild, lastChild, firstChild)
- // delete()
- // checkDelete()
- // deleteChildRange(firstChild, lastChild)
- // replace(this)
-
- Assert.assertTrue(isValid)
- isWritable
- reference
- references
- putCopyableUserData(TEST_DATA_KEY, 12)
-
- Assert.assertTrue(getCopyableUserData(TEST_DATA_KEY) == 12)
- // Assert.assertTrue(copy().getCopyableUserData(TEST_DATA_KEY) == 12) { this } Doesn't work
-
- // processDeclarations(...)
-
- context
- isPhysical
- resolveScope
- useScope
- node
- toString()
- Assert.assertTrue(isEquivalentTo(this))
- } catch (t: Throwable) {
- throw AssertionErrorWithCause("Failed for ${this::class.java} ${this}", t)
- }
- }
- }
+/*
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.caches.resolve
+
+import com.intellij.openapi.util.Key
+import com.intellij.psi.*
+import org.jetbrains.kotlin.asJava.elements.KtLightElement
+import org.jetbrains.kotlin.asJava.elements.KtLightModifierList
+import org.jetbrains.kotlin.idea.KotlinLanguage
+import org.junit.Assert
+
+object PsiElementChecker {
+ val TEST_DATA_KEY = Key.create<Int>("Test Key")
+
+ fun checkPsiElementStructure(lightClass: PsiClass) {
+ checkPsiElement(lightClass)
+
+ lightClass.methods.forEach {
+ it.parameterList.parameters.forEach { checkPsiElement(it) }
+ checkPsiElement(it)
+ }
+
+ lightClass.fields.forEach { checkPsiElement(it) }
+
+ lightClass.innerClasses.forEach { checkPsiElementStructure(it) }
+ }
+
+ private fun checkPsiElement(element: PsiElement) {
+ if (element !is KtLightElement<*, *> && element !is KtLightModifierList<*>) return
+
+ if (element is PsiModifierListOwner) {
+ val modifierList = element.modifierList
+ if (modifierList != null) {
+ checkPsiElement(modifierList)
+ }
+ }
+
+ if (element is PsiTypeParameterListOwner) {
+ val typeParameterList = element.typeParameterList
+ if (typeParameterList != null) {
+ checkPsiElement(typeParameterList)
+ typeParameterList.typeParameters.forEach { checkPsiElement(it) }
+ }
+ }
+
+ with(element) {
+ try {
+ Assert.assertEquals("Number of methods has changed. Please update test.", 56, PsiElement::class.java.methods.size)
+
+ project
+ Assert.assertTrue(language == KotlinLanguage.INSTANCE)
+ manager
+ children
+ parent
+ firstChild
+ lastChild
+ nextSibling
+ prevSibling
+ containingFile
+ textRange
+ //textRangeInParent - throws an exception for non-physical elements, it is expected behaviour
+ startOffsetInParent
+ textLength
+ findElementAt(0)
+ findReferenceAt(0)
+ textOffset
+ text
+ textToCharArray()
+ navigationElement
+ originalElement
+ textMatches("")
+ Assert.assertTrue(textMatches(this))
+ textContains('a')
+ accept(PsiElementVisitor.EMPTY_VISITOR)
+ acceptChildren(PsiElementVisitor.EMPTY_VISITOR)
+
+ val copy = copy()
+ Assert.assertTrue(copy == null || copy::class.java == this::class.java)
+
+ // Modify methods:
+ // add(this)
+ // addBefore(this, lastChild)
+ // addAfter(firstChild, this)
+ // checkAdd(this)
+ // addRange(firstChild, lastChild)
+ // addRangeBefore(firstChild, lastChild, lastChild)
+ // addRangeAfter(firstChild, lastChild, firstChild)
+ // delete()
+ // checkDelete()
+ // deleteChildRange(firstChild, lastChild)
+ // replace(this)
+
+ Assert.assertTrue(isValid)
+ isWritable
+ @Suppress("UnstableApiUsage") ownReferences
+ reference
+ references
+ putCopyableUserData(TEST_DATA_KEY, 12)
+
+ Assert.assertTrue(getCopyableUserData(TEST_DATA_KEY) == 12)
+ // Assert.assertTrue(copy().getCopyableUserData(TEST_DATA_KEY) == 12) { this } Doesn't work
+
+ // processDeclarations(...)
+
+ context
+ isPhysical
+ resolveScope
+ useScope
+ node
+ toString()
+ Assert.assertTrue(isEquivalentTo(this))
+ } catch (t: Throwable) {
+ throw AssertionErrorWithCause("Failed for ${this::class.java} ${this}", t)
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/PsiElementChecker.kt.193 b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/PsiElementChecker.kt.193
new file mode 100644
index 0000000..d6ef5152
--- /dev/null
+++ b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/PsiElementChecker.kt.193
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.caches.resolve
+
+import com.intellij.openapi.util.Key
+import com.intellij.psi.*
+import org.jetbrains.kotlin.asJava.elements.KtLightElement
+import org.jetbrains.kotlin.asJava.elements.KtLightModifierList
+import org.jetbrains.kotlin.idea.KotlinLanguage
+import org.junit.Assert
+
+object PsiElementChecker {
+ val TEST_DATA_KEY = Key.create<Int>("Test Key")
+
+ fun checkPsiElementStructure(lightClass: PsiClass) {
+ checkPsiElement(lightClass)
+
+ lightClass.methods.forEach {
+ it.parameterList.parameters.forEach { checkPsiElement(it) }
+ checkPsiElement(it)
+ }
+
+ lightClass.fields.forEach { checkPsiElement(it) }
+
+ lightClass.innerClasses.forEach { checkPsiElementStructure(it) }
+ }
+
+ private fun checkPsiElement(element: PsiElement) {
+ if (element !is KtLightElement<*, *> && element !is KtLightModifierList<*>) return
+
+ if (element is PsiModifierListOwner) {
+ val modifierList = element.modifierList
+ if (modifierList != null) {
+ checkPsiElement(modifierList)
+ }
+ }
+
+ if (element is PsiTypeParameterListOwner) {
+ val typeParameterList = element.typeParameterList
+ if (typeParameterList != null) {
+ checkPsiElement(typeParameterList)
+ typeParameterList.typeParameters.forEach { checkPsiElement(it) }
+ }
+ }
+
+ with(element) {
+ try {
+ Assert.assertEquals("Number of methods has changed. Please update test.", 55, PsiElement::class.java.methods.size)
+
+ project
+ Assert.assertTrue(language == KotlinLanguage.INSTANCE)
+ manager
+ children
+ parent
+ firstChild
+ lastChild
+ nextSibling
+ prevSibling
+ containingFile
+ textRange
+ //textRangeInParent - throws an exception for non-physical elements, it is expected behaviour
+ startOffsetInParent
+ textLength
+ findElementAt(0)
+ findReferenceAt(0)
+ textOffset
+ text
+ textToCharArray()
+ navigationElement
+ originalElement
+ textMatches("")
+ Assert.assertTrue(textMatches(this))
+ textContains('a')
+ accept(PsiElementVisitor.EMPTY_VISITOR)
+ acceptChildren(PsiElementVisitor.EMPTY_VISITOR)
+
+ val copy = copy()
+ Assert.assertTrue(copy == null || copy::class.java == this::class.java)
+
+ // Modify methods:
+ // add(this)
+ // addBefore(this, lastChild)
+ // addAfter(firstChild, this)
+ // checkAdd(this)
+ // addRange(firstChild, lastChild)
+ // addRangeBefore(firstChild, lastChild, lastChild)
+ // addRangeAfter(firstChild, lastChild, firstChild)
+ // delete()
+ // checkDelete()
+ // deleteChildRange(firstChild, lastChild)
+ // replace(this)
+
+ Assert.assertTrue(isValid)
+ isWritable
+ reference
+ references
+ putCopyableUserData(TEST_DATA_KEY, 12)
+
+ Assert.assertTrue(getCopyableUserData(TEST_DATA_KEY) == 12)
+ // Assert.assertTrue(copy().getCopyableUserData(TEST_DATA_KEY) == 12) { this } Doesn't work
+
+ // processDeclarations(...)
+
+ context
+ isPhysical
+ resolveScope
+ useScope
+ node
+ toString()
+ Assert.assertTrue(isEquivalentTo(this))
+ } catch (t: Throwable) {
+ throw AssertionErrorWithCause("Failed for ${this::class.java} ${this}", t)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSignatureChangePresentationTest.kt b/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSignatureChangePresentationTest.kt
new file mode 100644
index 0000000..0c8605d
--- /dev/null
+++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSignatureChangePresentationTest.kt
@@ -0,0 +1,874 @@
+/*
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.refactoring.suggested
+
+import com.intellij.refactoring.suggested.SuggestedRefactoringSupport.Parameter
+import com.intellij.refactoring.suggested.SuggestedRefactoringSupport.Signature
+import com.intellij.refactoring.suggested.BaseSignatureChangePresentationTest
+
+class KotlinSignatureChangePresentationTest : BaseSignatureChangePresentationTest() {
+ override val refactoringSupport = KotlinSuggestedRefactoringSupport()
+
+ private fun signature(
+ name: String,
+ type: String?,
+ parameters: List<Parameter>,
+ receiverType: String? = null
+ ): Signature? {
+ return Signature.create(
+ name,
+ type,
+ parameters,
+ KotlinSignatureAdditionalData(DeclarationType.FUN, receiverType)
+ )
+ }
+
+ fun testAddParameters() {
+ val oldSignature = signature(
+ "foo",
+ "String",
+ listOf(Parameter(0, "p1", "Int")),
+ "Any"
+ )!!
+ val newSignature = signature(
+ "foo",
+ "String",
+ listOf(
+ Parameter(Any(), "p0", "Any"),
+ Parameter(0, "p1", "Int"),
+ Parameter(Any(), "p2", "Long")
+ ),
+ "Any"
+ )!!
+ doTest(
+ oldSignature,
+ newSignature,
+ """
+ Old:
+ 'fun '
+ 'Any.'
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group:
+ 'p1'
+ ': '
+ 'Int'
+ LineBreak('', false)
+ ')'
+ ': String'
+ New:
+ 'fun '
+ 'Any.'
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group (added):
+ 'p0'
+ ': '
+ 'Any'
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p1'
+ ': '
+ 'Int'
+ ','
+ LineBreak(' ', true)
+ Group (added):
+ 'p2'
+ ': '
+ 'Long'
+ LineBreak('', false)
+ ')'
+ ': String'
+ """.trimIndent()
+ )
+ }
+
+ fun testSwapParameters() {
+ val oldSignature = signature(
+ "foo",
+ null,
+ listOf(
+ Parameter(0, "p1", "Int"),
+ Parameter(1, "p2", "Long")
+ )
+ )!!
+ val newSignature = signature(
+ "foo",
+ null,
+ listOf(
+ Parameter(1, "p2", "Long"),
+ Parameter(0, "p1", "Int")
+ )
+ )!!
+ doTest(
+ oldSignature,
+ newSignature,
+ """
+ Old:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group (moved):
+ 'p1'
+ ': '
+ 'Int'
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p2'
+ ': '
+ 'Long'
+ LineBreak('', false)
+ ')'
+ New:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group:
+ 'p2'
+ ': '
+ 'Long'
+ ','
+ LineBreak(' ', true)
+ Group (moved):
+ 'p1'
+ ': '
+ 'Int'
+ LineBreak('', false)
+ ')'
+ """.trimIndent()
+ )
+ }
+
+ fun testMoveParameter() {
+ val oldSignature = signature(
+ "foo",
+ null,
+ listOf(
+ Parameter(0, "p1", "Int"),
+ Parameter(1, "p2", "Long"),
+ Parameter(2, "p3", "Any")
+ )
+ )!!
+ val newSignature = signature(
+ "foo",
+ null,
+ listOf(
+ Parameter(1, "p2", "Long"),
+ Parameter(2, "p3", "Any"),
+ Parameter(0, "p1", "Int")
+ )
+ )!!
+ doTest(
+ oldSignature,
+ newSignature,
+ """
+ Old:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group (moved):
+ 'p1'
+ ': '
+ 'Int'
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p2'
+ ': '
+ 'Long'
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p3'
+ ': '
+ 'Any'
+ LineBreak('', false)
+ ')'
+ New:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group:
+ 'p2'
+ ': '
+ 'Long'
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p3'
+ ': '
+ 'Any'
+ ','
+ LineBreak(' ', true)
+ Group (moved):
+ 'p1'
+ ': '
+ 'Int'
+ LineBreak('', false)
+ ')'
+ """.trimIndent()
+ )
+ }
+
+ fun testReorderParameters() {
+ val oldSignature = signature(
+ "foo",
+ null,
+ listOf(
+ Parameter(0, "p1", "Int"),
+ Parameter(1, "p2", "Long"),
+ Parameter(2, "p3", "Any"),
+ Parameter(3, "p4", "Any")
+ )
+ )!!
+ val newSignature = signature(
+ "foo",
+ null,
+ listOf(
+ Parameter(1, "p2", "Long"),
+ Parameter(3, "p4", "Any"),
+ Parameter(2, "p3", "Any"),
+ Parameter(0, "p1", "Int")
+ )
+ )!!
+ doTest(
+ oldSignature,
+ newSignature,
+ """
+ Old:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group (id = 0, moved):
+ 'p1'
+ ': '
+ 'Int'
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p2'
+ ': '
+ 'Long'
+ ','
+ LineBreak(' ', true)
+ Group (id = 2, moved):
+ 'p3'
+ ': '
+ 'Any'
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p4'
+ ': '
+ 'Any'
+ LineBreak('', false)
+ ')'
+ New:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group:
+ 'p2'
+ ': '
+ 'Long'
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p4'
+ ': '
+ 'Any'
+ ','
+ LineBreak(' ', true)
+ Group (id = 2, moved):
+ 'p3'
+ ': '
+ 'Any'
+ ','
+ LineBreak(' ', true)
+ Group (id = 0, moved):
+ 'p1'
+ ': '
+ 'Int'
+ LineBreak('', false)
+ ')'
+ """.trimIndent()
+ )
+ }
+
+ fun testChangeFunctionName() {
+ val oldSignature = signature("foo", null, emptyList())!!
+ val newSignature = signature("bar", null, emptyList())!!
+ doTest(
+ oldSignature,
+ newSignature,
+ """
+ Old:
+ 'fun '
+ 'foo' (modified)
+ '('
+ LineBreak('', false)
+ ')'
+ New:
+ 'fun '
+ 'bar' (modified)
+ '('
+ LineBreak('', false)
+ ')'
+ """.trimIndent()
+ )
+ }
+
+ fun testChangeReturnType() {
+ val oldSignature = signature("foo", "Any", emptyList())!!
+ val newSignature = signature("foo", "String", emptyList())!!
+ doTest(
+ oldSignature,
+ newSignature,
+ """
+ Old:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', false)
+ ')'
+ ': '
+ 'Any' (modified)
+ New:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', false)
+ ')'
+ ': '
+ 'String' (modified)
+ """.trimIndent()
+ )
+ }
+
+ fun testAddReturnType() {
+ val oldSignature = signature("foo", null, emptyList())!!
+ val newSignature = signature("foo", "String", emptyList())!!
+ doTest(
+ oldSignature,
+ newSignature,
+ """
+ Old:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', false)
+ ')'
+ New:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', false)
+ ')'
+ ': String' (added)
+ """.trimIndent()
+ )
+ }
+
+ fun testRemoveReturnType() {
+ val oldSignature = signature("foo", "Any", emptyList())!!
+ val newSignature = signature("foo", null, emptyList())!!
+ doTest(
+ oldSignature,
+ newSignature,
+ """
+ Old:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', false)
+ ')'
+ ': Any' (removed)
+ New:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', false)
+ ')'
+ """.trimIndent()
+ )
+ }
+
+ fun testChangeParameterName() {
+ val oldSignature = signature(
+ "foo",
+ null,
+ listOf(
+ Parameter(0, "p1", "Int"),
+ Parameter(1, "p2", "Long")
+ )
+ )!!
+ val newSignature = signature(
+ "foo",
+ null,
+ listOf(
+ Parameter(0, "p1New", "Int"),
+ Parameter(1, "p2", "Long")
+ )
+ )!!
+ doTest(
+ oldSignature,
+ newSignature,
+ """
+ Old:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group:
+ 'p1' (modified)
+ ': '
+ 'Int'
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p2'
+ ': '
+ 'Long'
+ LineBreak('', false)
+ ')'
+ New:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group:
+ 'p1New' (modified)
+ ': '
+ 'Int'
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p2'
+ ': '
+ 'Long'
+ LineBreak('', false)
+ ')'
+""".trimIndent()
+ )
+ }
+
+ fun testChangeTwoParameterNames() {
+ val oldSignature = signature(
+ "foo",
+ null,
+ listOf(
+ Parameter(0, "p1", "Int"),
+ Parameter(1, "p2", "Long")
+ )
+ )!!
+ val newSignature = signature(
+ "foo",
+ null,
+ listOf(
+ Parameter(0, "p1New", "Int"),
+ Parameter(1, "p2New", "Long")
+ )
+ )!!
+ doTest(
+ oldSignature,
+ newSignature,
+ """
+ Old:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group:
+ 'p1' (modified)
+ ': '
+ 'Int'
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p2' (modified)
+ ': '
+ 'Long'
+ LineBreak('', false)
+ ')'
+ New:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group:
+ 'p1New' (modified)
+ ': '
+ 'Int'
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p2New' (modified)
+ ': '
+ 'Long'
+ LineBreak('', false)
+ ')'
+ """.trimIndent()
+ )
+ }
+
+ fun testMoveAndRenameParameter() {
+ val oldSignature = signature(
+ "foo",
+ null,
+ listOf(
+ Parameter(0, "p1", "Int"),
+ Parameter(1, "p2", "Long"),
+ Parameter(2, "p3", "Any")
+ )
+ )!!
+ val newSignature = signature(
+ "foo",
+ null,
+ listOf(
+ Parameter(1, "p2", "Long"),
+ Parameter(2, "p3", "Any"),
+ Parameter(0, "p1New", "Int")
+ )
+ )!!
+ doTest(
+ oldSignature,
+ newSignature,
+ """
+ Old:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group (moved):
+ 'p1' (modified)
+ ': '
+ 'Int'
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p2'
+ ': '
+ 'Long'
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p3'
+ ': '
+ 'Any'
+ LineBreak('', false)
+ ')'
+ New:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group:
+ 'p2'
+ ': '
+ 'Long'
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p3'
+ ': '
+ 'Any'
+ ','
+ LineBreak(' ', true)
+ Group (moved):
+ 'p1New' (modified)
+ ': '
+ 'Int'
+ LineBreak('', false)
+ ')'
+ """.trimIndent()
+ )
+ }
+
+ fun testMoveParameterAndChangeFunctionName() {
+ val oldSignature = signature(
+ "foo",
+ null,
+ listOf(
+ Parameter(0, "p1", "Int"),
+ Parameter(1, "p2", "Long"),
+ Parameter(2, "p3", "Any")
+ )
+ )!!
+ val newSignature = signature(
+ "fooNew",
+ null,
+ listOf(
+ Parameter(1, "p2", "Long"),
+ Parameter(2, "p3", "Any"),
+ Parameter(0, "p1", "Int")
+ )
+ )!!
+ doTest(
+ oldSignature,
+ newSignature,
+ """
+ Old:
+ 'fun '
+ 'foo' (modified)
+ '('
+ LineBreak('', true)
+ Group (id = 0, moved):
+ 'p1'
+ ': '
+ 'Int'
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p2'
+ ': '
+ 'Long'
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p3'
+ ': '
+ 'Any'
+ LineBreak('', false)
+ ')'
+ New:
+ 'fun '
+ 'fooNew' (modified)
+ '('
+ LineBreak('', true)
+ Group:
+ 'p2'
+ ': '
+ 'Long'
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p3'
+ ': '
+ 'Any'
+ ','
+ LineBreak(' ', true)
+ Group (id = 0, moved):
+ 'p1'
+ ': '
+ 'Int'
+ LineBreak('', false)
+ ')'
+ """.trimIndent()
+ )
+ }
+
+ fun testAddReceiver() {
+ val oldSignature = signature(
+ "foo",
+ null,
+ emptyList()
+ )!!
+ val newSignature = signature(
+ "foo",
+ null,
+ emptyList(),
+ "Any"
+ )!!
+ doTest(
+ oldSignature,
+ newSignature,
+ """
+ Old:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', false)
+ ')'
+ New:
+ 'fun '
+ 'Any.' (added)
+ 'foo'
+ '('
+ LineBreak('', false)
+ ')'
+ """.trimIndent()
+ )
+ }
+
+ fun testRemoveReceiver() {
+ val oldSignature = signature(
+ "foo",
+ null,
+ emptyList(),
+ "Any"
+ )!!
+ val newSignature = signature(
+ "foo",
+ null,
+ emptyList()
+ )!!
+ doTest(
+ oldSignature,
+ newSignature,
+ """
+ Old:
+ 'fun '
+ 'Any.' (removed)
+ 'foo'
+ '('
+ LineBreak('', false)
+ ')'
+ New:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', false)
+ ')'
+ """.trimIndent()
+ )
+ }
+
+ fun testChangeReceiverType() {
+ val oldSignature = signature(
+ "foo",
+ null,
+ emptyList(),
+ "Any"
+ )!!
+ val newSignature = signature(
+ "foo",
+ null,
+ emptyList(),
+ "String"
+ )!!
+ doTest(
+ oldSignature,
+ newSignature,
+ """
+ Old:
+ 'fun '
+ 'Any' (modified)
+ '.'
+ 'foo'
+ '('
+ LineBreak('', false)
+ ')'
+ New:
+ 'fun '
+ 'String' (modified)
+ '.'
+ 'foo'
+ '('
+ LineBreak('', false)
+ ')'
+ """.trimIndent()
+ )
+ }
+
+ fun testChangeDefaultValues() {
+ val oldSignature = signature(
+ "foo",
+ null,
+ listOf(
+ Parameter(0, "p1", "Int", KotlinParameterAdditionalData("1", "")),
+ Parameter(1, "p2", "Int", KotlinParameterAdditionalData("2", "")),
+ Parameter(2, "p3", "Int", KotlinParameterAdditionalData("3", "")),
+ Parameter(3, "p4", "Int")
+ )
+ )!!
+ val newSignature = signature(
+ "foo",
+ null,
+ listOf(
+ Parameter(0, "p1", "Int", KotlinParameterAdditionalData("1", "")),
+ Parameter(1, "p2", "Int", KotlinParameterAdditionalData("22", "")),
+ Parameter(2, "p3", "Int"),
+ Parameter(3, "p4", "Int", KotlinParameterAdditionalData("4", ""))
+ )
+ )!!
+ doTest(
+ oldSignature,
+ newSignature,
+ """
+ Old:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group:
+ 'p1'
+ ': '
+ 'Int'
+ ' = '
+ '1'
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p2'
+ ': '
+ 'Int'
+ ' = '
+ '2' (modified)
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p3'
+ ': '
+ 'Int'
+ ' = ' (removed)
+ '3' (removed)
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p4'
+ ': '
+ 'Int'
+ LineBreak('', false)
+ ')'
+ New:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group:
+ 'p1'
+ ': '
+ 'Int'
+ ' = '
+ '1'
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p2'
+ ': '
+ 'Int'
+ ' = '
+ '22' (modified)
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p3'
+ ': '
+ 'Int'
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p4'
+ ': '
+ 'Int'
+ ' = ' (added)
+ '4' (added)
+ LineBreak('', false)
+ ')'
+ """.trimIndent()
+ )
+ }
+}
\ No newline at end of file
diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSignatureChangePresentationTest.kt.193 b/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSignatureChangePresentationTest.kt.193
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSignatureChangePresentationTest.kt.193
diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringAvailabilityTest.kt b/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringAvailabilityTest.kt
new file mode 100644
index 0000000..2b1b804
--- /dev/null
+++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringAvailabilityTest.kt
@@ -0,0 +1,371 @@
+package org.jetbrains.kotlin.idea.refactoring.suggested
+
+import com.intellij.openapi.fileTypes.LanguageFileType
+import com.intellij.refactoring.suggested.BaseSuggestedRefactoringAvailabilityTest
+import org.jetbrains.kotlin.idea.KotlinFileType
+import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
+import org.jetbrains.kotlin.psi.KtFile
+import org.jetbrains.kotlin.psi.KtPsiFactory
+import org.jetbrains.kotlin.resolve.ImportPath
+
+class KotlinSuggestedRefactoringAvailabilityTest : BaseSuggestedRefactoringAvailabilityTest() {
+ override val fileType: LanguageFileType
+ get() = KotlinFileType.INSTANCE
+
+ override fun getProjectDescriptor() = KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE
+
+ fun testNotAvailableWithSyntaxError() {
+ doTest(
+ """
+ fun foo(p1: Int<caret>) {
+ foo(1)
+ }
+
+ fun bar() {
+ foo(2)
+ }
+ """.trimIndent(),
+ {
+ myFixture.type(", p2: Any")
+ },
+ {
+ myFixture.type(", p")
+ },
+ expectedAvailability = Availability.Disabled
+ )
+ }
+
+ fun testInsertTrailingComma() {
+ doTest(
+ """
+ fun foo(p1: Int<caret>) {
+ foo(1)
+ }
+
+ fun bar() {
+ foo(2)
+ }
+ """.trimIndent(),
+ {
+ myFixture.type(",")
+ },
+ expectedAvailability = Availability.NotAvailable
+ )
+ }
+
+ fun testChangeNonVirtualPropertyType() {
+ doTest(
+ "val v: <caret>String = \"\"",
+ {
+ replaceTextAtCaret("String", "Any")
+ },
+ expectedAvailability = Availability.Disabled
+ )
+ }
+
+ fun testChangeParameterTypeNonVirtual() {
+ doTest(
+ "fun foo(p: <caret>String) {}",
+ {
+ replaceTextAtCaret("String", "Any")
+ },
+ expectedAvailability = Availability.Disabled
+ )
+ }
+
+ fun testChangeReturnTypeNonVirtual() {
+ doTest(
+ "fun foo(): <caret>String = \"\"",
+ {
+ replaceTextAtCaret("String", "Any")
+ },
+ expectedAvailability = Availability.Disabled
+ )
+ }
+
+ fun testChangeLocalVariableType() {
+ doTest(
+ """
+ fun foo() {
+ val local: <caret>Int
+ local = 10
+ }
+ """.trimIndent(),
+ {
+ replaceTextAtCaret("Int", "Long")
+ },
+ expectedAvailability = Availability.NotAvailable
+ )
+ }
+
+ fun testAddLocalVariableType() {
+ doTest(
+ """
+ fun foo() {
+ var local<caret> = 10
+ }
+ """.trimIndent(),
+ {
+ myFixture.type(": Long")
+ },
+ expectedAvailability = Availability.NotAvailable
+ )
+ }
+
+ fun testTypeLocalVariableBeforeExpression() {
+ doTest(
+ """
+ """.trimIndent(),
+ {
+ myFixture.type("val ")
+ },
+ {
+ myFixture.type("cod")
+ },
+ {
+ myFixture.type("e = ")
+ },
+ expectedAvailability = Availability.NotAvailable
+ )
+ }
+
+ fun testChangeParameterTypeAndName() {
+ doTest(
+ """
+ interface I {
+ fun foo(p: <caret>Int)
+ }
+ """.trimIndent(),
+ {
+ replaceTextAtCaret("Int", "String")
+ editor.caretModel.moveToOffset(editor.caretModel.offset - "p: ".length)
+ replaceTextAtCaret("p", "pNew")
+ },
+ expectedAvailability = Availability.Available(changeSignatureAvailableTooltip("foo", "usages"))
+ )
+ }
+
+ fun testRenameTwoParameters() {
+ doTest(
+ """
+ interface I {
+ fun foo(<caret>p1: Int, p2: Int)
+ }
+ """.trimIndent(),
+ {
+ replaceTextAtCaret("p1", "p1New")
+ },
+ {
+ editor.caretModel.moveToOffset(editor.caretModel.offset + "p1New: Int, ".length)
+ replaceTextAtCaret("p2", "p2New")
+ },
+ expectedAvailability = Availability.Available(changeSignatureAvailableTooltip("foo", "usages"))
+ )
+ }
+
+ fun testChangeParameterType() {
+ doTest(
+ """
+ class C {
+ open fun foo(p1: <caret>Int, p2: Int) {
+ }
+ }
+ """.trimIndent(),
+ {
+ replaceTextAtCaret("Int", "Any")
+ },
+ expectedAvailability = Availability.Available(changeSignatureAvailableTooltip("foo", "overrides"))
+ )
+ }
+
+ fun testChangeParameterTypeForAbstract() {
+ doTest(
+ """
+ abstract class C {
+ abstract fun foo(p1: <caret>Int, p2: Int)
+ }
+ """.trimIndent(),
+ {
+ replaceTextAtCaret("Int", "Any")
+ },
+ expectedAvailability = Availability.Available(changeSignatureAvailableTooltip("foo", "implementations"))
+ )
+ }
+
+ fun testChangeParameterTypeInInterface() {
+ doTest(
+ """
+ interface I {
+ fun foo(p1: <caret>Int, p2: Int)
+ }
+ """.trimIndent(),
+ {
+ replaceTextAtCaret("Int", "Any")
+ },
+ expectedAvailability = Availability.Available(changeSignatureAvailableTooltip("foo", "implementations"))
+ )
+ }
+
+ fun testChangeParameterTypeInInterfaceWithBody() {
+ doTest(
+ """
+ interface I {
+ fun foo(p1: <caret>Int, p2: Int) {}
+ }
+ """.trimIndent(),
+ {
+ replaceTextAtCaret("Int", "Any")
+ },
+ expectedAvailability = Availability.Available(changeSignatureAvailableTooltip("foo", "overrides"))
+ )
+ }
+
+ fun testChangeTypeOfPropertyWithImplementationInInterface() {
+ doTest(
+ """
+ interface I {
+ val p: <caret>Int
+ get() = 0
+ }
+ """.trimIndent(),
+ {
+ replaceTextAtCaret("Int", "Any")
+ },
+ expectedAvailability = Availability.Available(changeSignatureAvailableTooltip("p", "overrides"))
+ )
+ }
+
+ fun testSpecifyExplicitType() {
+ doTest(
+ """
+ open class C {
+ open fun foo()<caret> = 1
+ }
+ """.trimIndent(),
+ {
+ myFixture.type(": Int")
+ },
+ expectedAvailability = Availability.Available(changeSignatureAvailableTooltip("foo", "overrides")),
+ expectedAvailabilityAfterResolve = Availability.NotAvailable
+ )
+ }
+
+ fun testRemoveExplicitType() {
+ doTest(
+ """
+ open class C {
+ open fun foo(): Int<caret> = 1
+ }
+ """.trimIndent(),
+ {
+ deleteTextBeforeCaret(": Int")
+ },
+ expectedAvailability = Availability.Available(changeSignatureAvailableTooltip("foo", "overrides")),
+ expectedAvailabilityAfterResolve = Availability.NotAvailable
+ )
+ }
+
+ fun testImportNestedClass() {
+ doTest(
+ """
+ package ppp
+
+ class C {
+ class Nested
+ }
+
+ interface I {
+ fun foo(): <caret>C.Nested
+ }
+ """.trimIndent(),
+ {
+ addImport("ppp.C.Nested")
+ },
+ {
+ replaceTextAtCaret("C.Nested", "Nested")
+ },
+ expectedAvailability = Availability.Available(changeSignatureAvailableTooltip("foo", "implementations")),
+ expectedAvailabilityAfterResolve = Availability.NotAvailable
+ )
+ }
+
+ fun testImportNestedClassForReceiverType() {
+ doTest(
+ """
+ package ppp
+
+ class C {
+ class Nested
+ }
+
+ interface I {
+ fun <caret>C.Nested.foo()
+ }
+ """.trimIndent(),
+ {
+ addImport("ppp.C.Nested")
+ },
+ {
+ replaceTextAtCaret("C.Nested", "Nested")
+ },
+ expectedAvailability = Availability.Available(changeSignatureAvailableTooltip("foo", "implementations")),
+ expectedAvailabilityAfterResolve = Availability.NotAvailable
+ )
+ }
+
+ fun testImportNestedClassForParameterType() {
+ doTest(
+ """
+ package ppp
+
+ class C {
+ class Nested
+ }
+
+ interface I {
+ fun foo(p: <caret>C.Nested)
+ }
+ """.trimIndent(),
+ {
+ addImport("ppp.C.Nested")
+ },
+ {
+ replaceTextAtCaret("C.Nested", "Nested")
+ },
+ expectedAvailability = Availability.Available(changeSignatureAvailableTooltip("foo", "implementations")),
+ expectedAvailabilityAfterResolve = Availability.NotAvailable
+ )
+ }
+
+ fun testImportAnotherType() {
+ doTest(
+ """
+ import java.util.Date
+
+ interface I {
+ fun foo(): <caret>Date
+ }
+ """.trimIndent(),
+ {
+ replaceTextAtCaret("Date", "java.sql.Date")
+ },
+ {
+ removeImport("java.util.Date")
+ addImport("java.sql.Date")
+ },
+ {
+ replaceTextAtCaret("java.sql.Date", "Date")
+ },
+ expectedAvailability = Availability.NotAvailable,
+ expectedAvailabilityAfterResolve = Availability.Available((changeSignatureAvailableTooltip("foo", "implementations")))
+ )
+ }
+
+ private fun addImport(fqName: String) {
+ (file as KtFile).importList!!.add(KtPsiFactory(project).createImportDirective(ImportPath.fromString(fqName)))
+ }
+
+ private fun removeImport(fqName: String) {
+ (file as KtFile).importList!!.imports.first { it.importedFqName?.asString() == fqName }.delete()
+ }
+}
\ No newline at end of file
diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringAvailabilityTest.kt.193 b/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringAvailabilityTest.kt.193
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringAvailabilityTest.kt.193
diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringChangeCollectorTest.kt b/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringChangeCollectorTest.kt
new file mode 100644
index 0000000..e4da964
--- /dev/null
+++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringChangeCollectorTest.kt
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.refactoring.suggested
+
+import com.intellij.lang.Language
+import com.intellij.openapi.actionSystem.IdeActions
+import com.intellij.openapi.application.runWriteAction
+import com.intellij.openapi.command.executeCommand
+import com.intellij.openapi.fileTypes.FileType
+import com.intellij.psi.PsiDocumentManager
+import com.intellij.psi.PsiFile
+import com.intellij.refactoring.suggested.SuggestedRefactoringSupport.Parameter
+import com.intellij.refactoring.suggested.SuggestedRefactoringSupport.Signature
+import org.jetbrains.kotlin.idea.KotlinFileType
+import org.jetbrains.kotlin.idea.KotlinLanguage
+import com.intellij.refactoring.suggested.BaseSuggestedRefactoringChangeCollectorTest
+import org.jetbrains.kotlin.psi.*
+import org.jetbrains.kotlin.test.runTest
+
+class KotlinSuggestedRefactoringChangeCollectorTest : BaseSuggestedRefactoringChangeCollectorTest<KtNamedFunction>() {
+ override val fileType: FileType
+ get() = KotlinFileType.INSTANCE
+
+ override val language: Language
+ get() = KotlinLanguage.INSTANCE
+
+ override fun addDeclaration(file: PsiFile, text: String): KtNamedFunction {
+ val psiFactory = KtPsiFactory(project)
+ return (file as KtFile).add(psiFactory.createDeclaration(text)) as KtNamedFunction
+ }
+
+ override fun Signature.presentation(labelForParameterId: (Any) -> String?): String {
+ return buildString {
+ append("fun ")
+ val receiverType = (additionalData as KotlinSignatureAdditionalData?)?.receiverType
+ if (receiverType != null) {
+ append(receiverType)
+ append(".")
+ }
+ append(name)
+ append("(")
+ parameters.joinTo(this, separator = ", ") { it.presentation(labelForParameterId(it.id)) }
+ append(")")
+ if (type != null) {
+ append(": ")
+ append(type)
+ }
+ }
+ }
+
+ private fun Parameter.presentation(label: String?): String {
+ return buildString {
+ if (modifiers.isNotEmpty()) {
+ append(modifiers)
+ append(" ")
+ }
+ append(name)
+ append(": ")
+ append(type)
+ if (label != null) {
+ append(" (")
+ append(label)
+ append(")")
+ }
+ }
+ }
+
+ private fun createType(text: String): KtTypeReference {
+ return KtPsiFactory(project).createType(text)
+ }
+
+ private fun createParameter(text: String): KtParameter {
+ return KtPsiFactory(project).createParameter(text)
+ }
+
+ fun testAddParameter() {
+ doTest(
+ "fun foo(p1: Int) {}",
+ { it.valueParameterList!!.addParameter(createParameter("p2: Int")) },
+ expectedOldSignature = "fun foo(p1: Int)",
+ expectedNewSignature = "fun foo(p1: Int (initialIndex = 0), p2: Int (new))"
+ )
+ }
+
+ fun testRemoveParameter() {
+ doTest(
+ "fun foo(p1: Int, p2: Int) {}",
+ { it.valueParameterList!!.removeParameter(0) },
+ expectedOldSignature = "fun foo(p1: Int, p2: Int)",
+ expectedNewSignature = "fun foo(p2: Int (initialIndex = 1))"
+ )
+ }
+
+ fun testChangeParameterType() {
+ doTest(
+ "fun foo(p1: Int, p2: Int) {}",
+ { it.valueParameters[1].typeReference = createType("Any?") },
+ expectedOldSignature = "fun foo(p1: Int, p2: Int)",
+ expectedNewSignature = "fun foo(p1: Int (initialIndex = 0), p2: Any? (initialIndex = 1))"
+ )
+ }
+
+ fun testChangeParameterNames() {
+ doTest(
+ "fun foo(p1: Int, p2: Int) {}",
+ { it.valueParameters[0].setName("newP1") },
+ { it.valueParameters[1].setName("newP2") },
+ expectedOldSignature = "fun foo(p1: Int, p2: Int)",
+ expectedNewSignature = "fun foo(newP1: Int (initialIndex = 0), newP2: Int (initialIndex = 1))"
+ )
+ }
+
+ fun testReplaceParameter() {
+ doTest(
+ "fun foo(p1: Int, p2: Int) {}",
+ { it.valueParameters[0].replace(createParameter("newP1: Long")) },
+ expectedOldSignature = "fun foo(p1: Int, p2: Int)",
+ expectedNewSignature = "fun foo(newP1: Long (new), p2: Int (initialIndex = 1))"
+ )
+ }
+
+ fun testReorderParametersChangeTypesAndNames() {
+ doTest(
+ "fun foo(p1: Int, p2: Int, p3: Int) {}",
+ {
+ editor.caretModel.moveToOffset(it.valueParameters[2].textOffset)
+ myFixture.performEditorAction(IdeActions.MOVE_ELEMENT_LEFT)
+ myFixture.performEditorAction(IdeActions.MOVE_ELEMENT_LEFT)
+ },
+ {
+ executeCommand {
+ runWriteAction {
+ it.valueParameters[0].typeReference = createType("Any?")
+ it.valueParameters[1].typeReference = createType("Long")
+ it.valueParameters[2].typeReference = createType("Double")
+ }
+ }
+ },
+ {
+ executeCommand {
+ runWriteAction {
+ it.valueParameters[1].setName("newName")
+ }
+ }
+ },
+ wrapIntoCommandAndWriteAction = false,
+ expectedOldSignature = "fun foo(p1: Int, p2: Int, p3: Int)",
+ expectedNewSignature = "fun foo(p3: Any? (initialIndex = 2), newName: Long (initialIndex = 0), p2: Double (initialIndex = 1))"
+ )
+ }
+
+ fun testReorderParametersByCutPaste() {
+ doTest(
+ "fun foo(p1: Int, p2: String, p3: Char)",
+ {
+ val offset = it.valueParameters[1].textRange.endOffset
+ editor.caretModel.moveToOffset(offset)
+ editor.selectionModel.setSelection(offset, offset + ", p3: Char".length)
+ myFixture.performEditorAction(IdeActions.ACTION_EDITOR_CUT)
+ },
+ {
+ val offset = it.valueParameters[0].textRange.endOffset
+ editor.caretModel.moveToOffset(offset)
+ myFixture.performEditorAction(IdeActions.ACTION_EDITOR_PASTE)
+ },
+ wrapIntoCommandAndWriteAction = false,
+ expectedOldSignature = "fun foo(p1: Int, p2: String, p3: Char)",
+ expectedNewSignature = "fun foo(p1: Int (initialIndex = 0), p3: Char (initialIndex = 2), p2: String (initialIndex = 1))"
+ )
+ }
+
+ fun testReorderParametersByCutPasteAfterChangingName() {
+ doTest(
+ "fun foo(p1: Int, p2: String, p3: Char)",
+ {
+ executeCommand {
+ runWriteAction {
+ it.valueParameters[2].setName("p3New")
+ PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.document)
+ }
+ }
+ },
+ {
+ val offset = it.valueParameters[1].textRange.endOffset
+ editor.caretModel.moveToOffset(offset)
+ editor.selectionModel.setSelection(offset, offset + ", p3New: Char".length)
+ myFixture.performEditorAction(IdeActions.ACTION_EDITOR_CUT)
+ },
+ {
+ val offset = it.valueParameters[0].textRange.endOffset
+ editor.caretModel.moveToOffset(offset)
+ myFixture.performEditorAction(IdeActions.ACTION_EDITOR_PASTE)
+ },
+ wrapIntoCommandAndWriteAction = false,
+ expectedOldSignature = "fun foo(p1: Int, p2: String, p3: Char)",
+ expectedNewSignature = "fun foo(p1: Int (initialIndex = 0), p3New: Char (initialIndex = 2), p2: String (initialIndex = 1))"
+ )
+ }
+
+ override fun runTest() {
+ runTest { super.runTest() }
+ }
+}
diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringChangeCollectorTest.kt.193 b/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringChangeCollectorTest.kt.193
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringChangeCollectorTest.kt.193
diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringChangeListenerTest.kt b/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringChangeListenerTest.kt
new file mode 100644
index 0000000..d331dac
--- /dev/null
+++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringChangeListenerTest.kt
@@ -0,0 +1,400 @@
+/*
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.refactoring.suggested
+
+import com.intellij.openapi.actionSystem.IdeActions
+import com.intellij.openapi.application.runWriteAction
+import com.intellij.openapi.command.executeCommand
+import com.intellij.openapi.fileTypes.FileType
+import com.intellij.refactoring.suggested.BaseSuggestedRefactoringChangeListenerTest
+import org.jetbrains.kotlin.idea.KotlinFileType
+import org.jetbrains.kotlin.psi.*
+import org.jetbrains.kotlin.psi.psiUtil.endOffset
+import org.jetbrains.kotlin.psi.psiUtil.findDescendantOfType
+import org.jetbrains.kotlin.psi.psiUtil.startOffset
+import org.jetbrains.kotlin.resolve.ImportPath
+import org.jetbrains.kotlin.test.runTest
+
+class KotlinSuggestedRefactoringChangeListenerTest : BaseSuggestedRefactoringChangeListenerTest() {
+ override val fileType: FileType
+ get() = KotlinFileType.INSTANCE
+
+ fun test1() {
+ setup("fun foo(<caret>) {}")
+
+ perform("editingStarted: 'foo()'") { myFixture.type("p") }
+
+ perform("nextSignature: 'foo(p)'") { commitAll() }
+ perform { myFixture.type(":") }
+ perform { myFixture.type(" S") }
+ perform { myFixture.type("tr") }
+ perform("nextSignature: 'foo(p: Str)'") { commitAll() }
+ perform { myFixture.type("ing") }
+ perform("nextSignature: 'foo(p: String)'") { commitAll() }
+
+ perform {
+ perform { myFixture.type(", ") }
+ commitAll()
+ }
+ }
+
+ fun testCompletion() {
+ setup("fun foo(<caret>) {}")
+
+ perform("editingStarted: 'foo()'") { myFixture.type("p: DoubleArra") }
+ perform("nextSignature: 'foo(p: DoubleArra)'", "nextSignature: 'foo(p: DoubleArray)'") { myFixture.completeBasic() }
+ }
+
+ fun testChangeOutsideSignature() {
+ setup("fun foo(<caret>) {}")
+
+ perform("editingStarted: 'foo()'") { myFixture.type("p: A") }
+ perform("reset") {
+ insertString(editor.document.textLength, "\nval")
+ }
+ }
+
+ fun testEditOtherSignature() {
+ setup("fun foo(<caret>) {}\nfun bar() = 0")
+
+ val otherFunction = (file as KtFile).declarations[1] as KtNamedFunction
+ val offset = otherFunction.valueParameterList!!.startOffset + 1
+ val marker = editor.document.createRangeMarker(offset, offset)
+
+ perform("editingStarted: 'foo()'") { myFixture.type("p: A") }
+ perform("nextSignature: 'foo(p: A)'") { commitAll() }
+
+ perform("reset", "editingStarted: 'bar()'", "nextSignature: 'bar(p1: String)'") {
+ assert(marker.isValid)
+ insertString(marker.startOffset, "p1: String")
+ commitAll()
+ }
+ }
+
+ fun testChangeInAnotherFile() {
+ setup("fun foo(<caret>) {}")
+
+ perform("editingStarted: 'foo()'") { myFixture.type("p: A") }
+ perform("reset") {
+ setup("")
+ myFixture.type(" ")
+ }
+ }
+
+ fun testAddImport() {
+ setup("fun foo(<caret>) {}")
+
+ perform("editingStarted: 'foo()'", "nextSignature: 'foo(p: Any)'") {
+ myFixture.type("p: Any")
+ commitAll()
+ }
+ perform("nextSignature: 'foo(p: Any)'", "nextSignature: 'foo(p: Any)'") {
+ addImport("java.util.ArrayList")
+ }
+ perform("nextSignature: 'foo(p: Any, p2: String)'") {
+ myFixture.type(", p2: String")
+ commitAll()
+ }
+ perform("nextSignature: 'foo(p: Any, p2: String)'", "nextSignature: 'foo(p: Any, p2: String)'") {
+ addImport("java.util.Date")
+ }
+ }
+
+ fun testAddImportWithBlankLineInsertion() {
+ setup(
+ """
+ import foo.bar
+ fun foo(<caret>) {}
+ """.trimIndent()
+ )
+
+ perform("editingStarted: 'foo()'", "nextSignature: 'foo(p: ArrayList)'") {
+ myFixture.type("p: ArrayList")
+ commitAll()
+ }
+ perform("nextSignature: 'foo(p: ArrayList)'", "nextSignature: 'foo(p: ArrayList)'") {
+ addImport("java.util.ArrayList")
+ }
+ perform("nextSignature: 'foo(p: ArrayList<String>)'") {
+ myFixture.type("<String>")
+ commitAll()
+ }
+ perform("nextSignature: 'foo(p: ArrayList<String>, p2: Any)'") {
+ myFixture.type(", p2: Any")
+ commitAll()
+ }
+ }
+
+ fun testAddImportWithBlankLinesRemoval() {
+ setup(
+ """
+ import foo.bar
+
+
+
+ fun foo(<caret>) {}
+ """.trimIndent()
+ )
+
+ perform("editingStarted: 'foo()'", "nextSignature: 'foo(p: ArrayList)'") {
+ myFixture.type("p: ArrayList")
+ commitAll()
+ }
+ perform("nextSignature: 'foo(p: ArrayList)'", "nextSignature: 'foo(p: ArrayList)'") {
+ addImport("java.util.ArrayList")
+ }
+ perform("nextSignature: 'foo(p: ArrayList<String>)'") {
+ myFixture.type("<String>")
+ commitAll()
+ }
+ perform("nextSignature: 'foo(p: ArrayList<String>, p2: Any)'") {
+ myFixture.type(", p2: Any")
+ commitAll()
+ }
+ }
+
+ fun testReorderParameters() {
+ setup("fun foo(p1: String, p2: Any, p3<caret>: Int) {}")
+
+ perform("editingStarted: 'foo(p1: String, p2: Any, p3: Int)'") {
+ myFixture.performEditorAction(IdeActions.MOVE_ELEMENT_LEFT)
+ }
+ perform("nextSignature: 'foo(p1: String, p3: Int, p2: Any)'") {
+ myFixture.performEditorAction(IdeActions.MOVE_ELEMENT_LEFT)
+ }
+ perform("nextSignature: 'foo(p3: Int, p1: String, p2: Any)'") {
+ commitAll()
+ }
+ perform("nextSignature: 'foo(p1: String, p3: Int, p2: Any)'") {
+ myFixture.performEditorAction(IdeActions.MOVE_ELEMENT_RIGHT)
+ commitAll()
+ }
+ }
+
+ fun testAddParameterViaPsi() {
+ setup("fun foo(p1: Int) {}")
+
+ val function = (file as KtFile).declarations.single() as KtFunction
+ perform(
+ "editingStarted: 'foo(p1: Int)'",
+ "nextSignature: 'foo(p1: Int,)'",
+ "nextSignature: 'foo(p1: Int,p2: Int)'",
+ "nextSignature: 'foo(p1: Int, p2: Int)'"
+ ) {
+ executeCommand {
+ runWriteAction {
+ function.valueParameterList!!.addParameter(KtPsiFactory(project).createParameter("p2: Int"))
+ }
+ }
+ }
+ }
+
+ fun testCommentTyping() {
+ setup("fun foo(<caret>) {}")
+
+ perform("editingStarted: 'foo()'", "nextSignature: 'foo(p1: Any)'") {
+ myFixture.type("p1: Any")
+ commitAll()
+ }
+
+ perform {
+ myFixture.type("/*")
+ commitAll()
+ }
+
+ perform {
+ myFixture.type(" this is comment for parameter")
+ commitAll()
+ }
+
+ perform("nextSignature: 'foo(p1: Any/* this is comment for parameter*/)'") {
+ myFixture.type("*/")
+ commitAll()
+ }
+
+ perform {
+ myFixture.type(", p2: Int /*")
+ commitAll()
+ }
+
+ perform {
+ myFixture.type("this is comment for another parameter")
+ commitAll()
+ }
+
+ perform("nextSignature: 'foo(p1: Any/* this is comment for parameter*/, p2: Int /*this is comment for another parameter*/)'") {
+ myFixture.type("*/")
+ commitAll()
+ }
+ }
+
+ fun testAddReturnType() {
+ setup(
+ """
+ interface I {
+ fun foo()<caret>
+ }
+ """.trimIndent()
+ )
+
+ perform("editingStarted: 'foo()'") { myFixture.type(": String") }
+
+ perform("nextSignature: 'foo(): String'") { commitAll() }
+ }
+
+ fun testNewLocal() {
+ setup(
+ """
+ fun foo() {
+ <caret>
+ print(a)
+ }
+ """.trimIndent()
+ )
+
+ perform {
+ myFixture.type("val a")
+ commitAll()
+ myFixture.type("bcd")
+ commitAll()
+ }
+ }
+
+ fun testNewFunction() {
+ setup(
+ """
+ interface I {
+ <caret>
+ }
+ """.trimIndent()
+ )
+
+ perform {
+ myFixture.type("fun foo_bar123(_p1: Int)")
+ commitAll()
+ }
+ }
+
+ fun testNewProperty() {
+ setup(
+ """
+ interface I {
+ <caret>
+ }
+ """.trimIndent()
+ )
+
+ perform {
+ myFixture.type("val prop: I")
+ commitAll()
+
+ myFixture.type("nt")
+ commitAll()
+ }
+ }
+
+ fun testNewLocalWithNewUsage() {
+ setup(
+ """
+ fun foo() {
+ <caret>
+ }
+ """.trimIndent()
+ )
+
+ perform {
+ myFixture.type("val a = 10")
+ myFixture.performEditorAction(IdeActions.ACTION_EDITOR_ENTER)
+ myFixture.type("print(a)")
+ commitAll()
+ }
+
+ perform("editingStarted: 'a'", "nextSignature: 'abcd'") {
+ val variable = file.findDescendantOfType<KtProperty>()!!
+ myFixture.editor.caretModel.moveToOffset(variable.nameIdentifier!!.endOffset)
+ myFixture.type("bcd")
+ commitAll()
+ }
+ }
+
+ fun testNewLocalBeforeExpression() {
+ setup(
+ """
+ fun foo(p: Int) {
+ <caret>p * p
+ }
+ """.trimIndent()
+ )
+
+ perform {
+ myFixture.type("val a")
+ commitAll()
+ }
+ perform {
+ myFixture.type("bcd = ")
+ commitAll()
+ }
+ }
+
+ fun testNewClassWithConstructor() {
+ setup("")
+
+ perform {
+ myFixture.type("class C")
+ commitAll()
+ }
+ perform {
+ myFixture.type("(p: Int)")
+ commitAll()
+ }
+ }
+
+ fun testNewSecondaryConstructor() {
+ setup(
+ """
+ class C {
+ <caret>
+ }
+ """.trimIndent()
+ )
+
+ perform {
+ myFixture.type("constructor(p1: Int)")
+ commitAll()
+ }
+ perform {
+ myFixture.type("(, p2: String)")
+ commitAll()
+ }
+ }
+
+ fun testRenameComponentVar() {
+ setup(
+ """
+ fun f() {
+ val (<caret>a, b) = f()
+ }
+ """.trimIndent()
+ )
+
+ perform("editingStarted: 'a'", "nextSignature: 'newa'") {
+ myFixture.type("new")
+ commitAll()
+ }
+ }
+
+ override fun runTest() {
+ runTest { super.runTest() }
+ }
+
+ private fun addImport(fqName: String) {
+ executeCommand {
+ runWriteAction {
+ (file as KtFile).importList!!.add(KtPsiFactory(project).createImportDirective(ImportPath.fromString(fqName)))
+ }
+ }
+ }
+}
diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringChangeListenerTest.kt.193 b/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringChangeListenerTest.kt.193
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringChangeListenerTest.kt.193
diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringTest.kt b/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringTest.kt
new file mode 100644
index 0000000..06258e9
--- /dev/null
+++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringTest.kt
@@ -0,0 +1,1553 @@
+/*
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.refactoring.suggested
+
+import com.intellij.openapi.actionSystem.IdeActions
+import com.intellij.openapi.application.runWriteAction
+import com.intellij.openapi.command.executeCommand
+import com.intellij.openapi.fileTypes.LanguageFileType
+import com.intellij.psi.PsiDocumentManager
+import com.intellij.refactoring.suggested.SuggestedRefactoringExecution
+import com.intellij.refactoring.suggested.BaseSuggestedRefactoringTest
+import com.intellij.refactoring.suggested._suggestedChangeSignatureNewParameterValuesForTests
+import com.intellij.testFramework.LightProjectDescriptor
+import org.jetbrains.kotlin.idea.KotlinFileType
+import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
+import org.jetbrains.kotlin.psi.KtFile
+import org.jetbrains.kotlin.psi.KtFunction
+import org.jetbrains.kotlin.psi.KtPsiFactory
+import org.jetbrains.kotlin.resolve.ImportPath
+
+class KotlinSuggestedRefactoringTest : BaseSuggestedRefactoringTest() {
+ override val fileType: LanguageFileType
+ get() = KotlinFileType.INSTANCE
+
+ override fun setUp() {
+ super.setUp()
+ _suggestedChangeSignatureNewParameterValuesForTests = {
+ SuggestedRefactoringExecution.NewParameterValue.Expression(KtPsiFactory(project).createExpression("default$it"))
+ }
+ }
+
+ override fun getProjectDescriptor() = KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE
+
+ fun testAddParameter() {
+ ignoreErrorsAfter = true
+ doTestChangeSignature(
+ """
+ fun foo(p1: Int<caret>) {
+ foo(1)
+ }
+
+ fun bar() {
+ foo(2)
+ }
+ """.trimIndent(),
+ """
+ fun foo(p1: Int, p2: Any<caret>) {
+ foo(1, default0)
+ }
+
+ fun bar() {
+ foo(2, default0)
+ }
+ """.trimIndent(),
+ "usages",
+ { myFixture.type(", p2: Any") }
+ )
+ }
+
+ fun testRemoveParameter() {
+ doTestChangeSignature(
+ """
+ fun foo(p1: Any?, p2: Int<caret>) {
+ foo(null, 1)
+ }
+
+ fun bar() {
+ foo(1, 2)
+ }
+ """.trimIndent(),
+ """
+ fun foo(p1: Any?<caret>) {
+ foo(null)
+ }
+
+ fun bar() {
+ foo(1)
+ }
+ """.trimIndent(),
+ "usages",
+ {
+ deleteTextBeforeCaret(", p2: Int")
+ }
+ )
+ }
+
+ fun testReorderParameters1() {
+ doTestChangeSignature(
+ """
+ fun foo(p1: Any?, p2: Int, p3: Boolean<caret>) {
+ foo(null, 1, true)
+ }
+
+ fun bar() {
+ foo(1, 2, false)
+ }
+ """.trimIndent(),
+ """
+ fun foo(p3: Boolean, p1: Any?, p2: Int) {
+ foo(true, null, 1)
+ }
+
+ fun bar() {
+ foo(false, 1, 2)
+ }
+ """.trimIndent(),
+ "usages",
+ { myFixture.performEditorAction(IdeActions.MOVE_ELEMENT_LEFT) },
+ { myFixture.performEditorAction(IdeActions.MOVE_ELEMENT_LEFT) },
+ wrapIntoCommandAndWriteAction = false
+ )
+ }
+
+ fun testReorderParameters2() {
+ doTestChangeSignature(
+ """
+ fun foo(p1: Any?, <caret>p2: Int, p3: Boolean) {
+ foo(null, 1, true)
+ }
+
+ fun bar() {
+ foo(1, 2, false)
+ }
+ """.trimIndent(),
+ """
+ fun foo(p2: Int, p1: Any?, p3: Boolean) {
+ foo(1, null, true)
+ }
+
+ fun bar() {
+ foo(2, 1, false)
+ }
+ """.trimIndent(),
+ "usages",
+ {
+ myFixture.performEditorAction(IdeActions.ACTION_EDITOR_SELECT_WORD_AT_CARET)
+ myFixture.performEditorAction(IdeActions.ACTION_EDITOR_SELECT_WORD_AT_CARET)
+ myFixture.performEditorAction(IdeActions.ACTION_EDITOR_CUT)
+ },
+ {
+ editor.caretModel.moveToOffset(editor.caretModel.offset - 10)
+ myFixture.performEditorAction(IdeActions.ACTION_EDITOR_PASTE)
+ },
+ {
+ myFixture.type(", ")
+ },
+ {
+ editor.caretModel.moveToOffset(editor.caretModel.offset + 10)
+ myFixture.performEditorAction(IdeActions.ACTION_EDITOR_DELETE)
+ myFixture.performEditorAction(IdeActions.ACTION_EDITOR_DELETE)
+ },
+ wrapIntoCommandAndWriteAction = false
+ )
+ }
+
+ fun testChangeParameterType() {
+ doTestChangeSignature(
+ """
+ interface I {
+ fun foo(p: <caret>String)
+ }
+
+ class C : I {
+ override fun foo(p: String) {
+ }
+ }
+ """.trimIndent(),
+ """
+ interface I {
+ fun foo(p: <caret>Any)
+ }
+
+ class C : I {
+ override fun foo(p: Any) {
+ }
+ }
+ """.trimIndent(),
+ "implementations",
+ {
+ replaceTextAtCaret("String", "Any")
+ }
+ )
+ }
+
+ fun testChangeParameterTypeExpectFunction() {
+ ignoreErrorsBefore = true
+ ignoreErrorsAfter = true
+ doTestChangeSignature(
+ "expect fun foo(p: <caret>String)",
+ "expect fun foo(p: <caret>Any)",
+ "actual declarations",
+ {
+ replaceTextAtCaret("String", "Any")
+ }
+ )
+ }
+
+ fun testUnresolvedParameterType() {
+ ignoreErrorsAfter = true
+ doTestChangeSignature(
+ """
+ interface I {
+ fun foo(p: <caret>String)
+ }
+
+ class C : I {
+ override fun foo(p: String) {
+ }
+ }
+ """.trimIndent(),
+ """
+ interface I {
+ fun foo(p: XXX)
+ }
+
+ class C : I {
+ override fun foo(p: XXX) {
+ }
+ }
+ """.trimIndent(),
+ "implementations",
+ {
+ replaceTextAtCaret("String", "XXX")
+ }
+ )
+ }
+
+ fun testChangeParameterTypeWithImportInsertion() {
+ myFixture.addFileToProject(
+ "X.kt",
+ """
+ package xxx
+ class X
+ """.trimIndent()
+ )
+
+ val otherFile = myFixture.addFileToProject(
+ "Other.kt",
+ """
+ class D : I {
+ override fun foo(p: String) {
+ }
+ }
+ """.trimIndent()
+ )
+
+ doTestChangeSignature(
+ """
+ interface I {
+ fun foo(p: <caret>String)
+ }
+
+ class C : I {
+ override fun foo(p: String) {
+ }
+ }
+ """.trimIndent(),
+ """
+ import xxx.X
+
+ interface I {
+ fun foo(p: <caret>X)
+ }
+
+ class C : I {
+ override fun foo(p: X) {
+ }
+ }
+ """.trimIndent(),
+ "implementations",
+ {
+ replaceTextAtCaret("String", "X")
+ },
+ {
+ addImport("xxx.X")
+ }
+ )
+
+ assertEquals(
+ """
+ import xxx.X
+
+ class D : I {
+ override fun foo(p: X) {
+ }
+ }
+ """.trimIndent(),
+ otherFile.text
+ )
+ }
+
+ fun testChangeReturnType() {
+ doTestChangeSignature(
+ """
+ interface I {
+ fun foo(): <caret>String
+ }
+
+ class C : I {
+ override fun foo(): String = ""
+ }
+ """.trimIndent(),
+ """
+ interface I {
+ fun foo(): <caret>Any
+ }
+
+ class C : I {
+ override fun foo(): Any = ""
+ }
+ """.trimIndent(),
+ "implementations",
+ {
+ replaceTextAtCaret("String", "Any")
+ }
+ )
+ }
+
+ fun testAddReturnType() {
+ ignoreErrorsAfter = true
+ doTestChangeSignature(
+ """
+ interface I {
+ fun foo()<caret>
+ }
+
+ class C : I {
+ override fun foo() {}
+ }
+ """.trimIndent(),
+ """
+ interface I {
+ fun foo(): String<caret>
+ }
+
+ class C : I {
+ override fun foo(): String {}
+ }
+ """.trimIndent(),
+ "implementations",
+ {
+ myFixture.type(": String")
+ }
+ )
+ }
+
+ fun testRemoveReturnType() {
+ ignoreErrorsAfter = true
+ doTestChangeSignature(
+ """
+ interface I {
+ fun foo()<caret>: String
+ }
+
+ class C : I {
+ override fun foo(): String = ""
+ }
+ """.trimIndent(),
+ """
+ interface I {
+ fun foo()<caret>
+ }
+
+ class C : I {
+ override fun foo() = ""
+ }
+ """.trimIndent(),
+ "implementations",
+ {
+ deleteTextAtCaret(": String")
+ }
+ )
+ }
+
+ fun testRenameAndAddReturnType() {
+ ignoreErrorsAfter = true
+ doTestChangeSignature(
+ """
+ interface I {
+ fun foo<caret>()
+ }
+
+ class C : I {
+ override fun foo() {}
+ }
+ """.trimIndent(),
+ """
+ interface I {
+ fun foo<caret>New(): String
+ }
+
+ class C : I {
+ override fun fooNew(): String {}
+ }
+ """.trimIndent(),
+ "usages",
+ {
+ val offset = editor.caretModel.offset
+ editor.document.insertString(offset, "New")
+ },
+ {
+ val offset = editor.caretModel.offset
+ editor.document.insertString(offset + "New()".length, ": String")
+ }
+ )
+ }
+
+ fun testChangeParameterTypeWithImportReplaced() {
+ myFixture.addFileToProject(
+ "XY.kt",
+ """
+ package xxx
+ class X
+ class Y
+ """.trimIndent()
+ )
+
+ val otherFile = myFixture.addFileToProject(
+ "Other.kt",
+ """
+ import xxx.X
+
+ class D : I {
+ override fun foo(p: X) {
+ }
+ }
+ """.trimIndent()
+ )
+
+ doTestChangeSignature(
+ """
+ import xxx.X
+
+ interface I {
+ fun foo(p: <caret>X)
+ }
+ """.trimIndent(),
+ """
+ import xxx.Y
+
+ interface I {
+ fun foo(p: <caret>Y)
+ }
+ """.trimIndent(),
+ "implementations",
+ {
+ val offset = editor.caretModel.offset
+ editor.document.replaceString(offset, offset + "X".length, "Y")
+ },
+ {
+ addImport("xxx.Y")
+ removeImport("xxx.X")
+ }
+ )
+
+ assertEquals(
+ """
+ import xxx.Y
+
+ class D : I {
+ override fun foo(p: Y) {
+ }
+ }
+ """.trimIndent(),
+ otherFile.text
+ )
+ }
+
+ fun testPreserveCommentsAndFormatting() {
+ doTestChangeSignature(
+ """
+ class A : I {
+ override fun foo() {
+ }
+ }
+
+ interface I {
+ fun foo(<caret>)
+ }
+ """.trimIndent(),
+ """
+ class A : I {
+ override fun foo(p1: Int, p2: Long, p3: Any?) {
+ }
+ }
+
+ interface I {
+ fun foo(p1: Int/*comment 1*/, p2: Long/*comment 2*/,
+ p3: Any?/*comment 3*/<caret>)
+ }
+ """.trimIndent(),
+ "usages",
+ {
+ myFixture.type("p1: Int/*comment 1*/")
+ },
+ {
+ myFixture.type(", p2: Long/*comment 2*/")
+ },
+ {
+ myFixture.type(",")
+ myFixture.performEditorAction(IdeActions.ACTION_EDITOR_ENTER)
+ myFixture.type("p3: Any?/*comment 3*/")
+ },
+ wrapIntoCommandAndWriteAction = false
+ )
+ }
+
+ fun testParameterCompletion() {
+ ignoreErrorsAfter = true
+ doTestChangeSignature(
+ "package ppp\nclass Abcdef\nfun foo(<caret>p: Int) { }\nfun bar() { foo(1) }",
+ "package ppp\nclass Abcdef\nfun foo(abcdef: Abcdef, <caret>p: Int) { }\nfun bar() { foo(default0, 1) }",
+ "usages",
+ {
+ executeCommand {
+ runWriteAction {
+ myFixture.type("abcde")
+ PsiDocumentManager.getInstance(project).commitAllDocuments()
+ }
+ }
+ },
+ {
+ myFixture.completeBasic()
+ },
+ {
+ myFixture.finishLookup('\n')
+ },
+ {
+ executeCommand {
+ runWriteAction {
+ myFixture.type(", ")
+ PsiDocumentManager.getInstance(project).commitAllDocuments()
+ }
+ }
+ },
+ wrapIntoCommandAndWriteAction = false
+ )
+ }
+
+ fun testRenameTwoParameters() {
+ doTestChangeSignature(
+ """
+ fun foo(<caret>p1: Int, p2: String) {
+ p1.hashCode()
+ p2.hashCode()
+ }
+ """.trimIndent(),
+ """
+ fun foo(<caret>p1New: Int, p2New: String) {
+ p1New.hashCode()
+ p2New.hashCode()
+ }
+ """.trimIndent(),
+ "usages",
+ {
+ val function = (file as KtFile).declarations.single() as KtFunction
+ function.valueParameters[0].setName("p1New")
+ function.valueParameters[1].setName("p2New")
+ }
+ )
+ }
+
+ fun testChangePropertyType() {
+ doTestChangeSignature(
+ """
+ interface I {
+ var v: <caret>String
+ }
+
+ class C : I {
+ override var v: String = ""
+ }
+ """.trimIndent(),
+ """
+ interface I {
+ var v: <caret>Any
+ }
+
+ class C : I {
+ override var v: Any = ""
+ }
+ """.trimIndent(),
+ "implementations",
+ {
+ replaceTextAtCaret("String", "Any")
+ },
+ expectedPresentation = """
+ Old:
+ 'var '
+ 'v'
+ ': '
+ 'String' (modified)
+ New:
+ 'var '
+ 'v'
+ ': '
+ 'Any' (modified)
+ """.trimIndent()
+ )
+ }
+
+ fun testRenameClass() {
+ doTestRename(
+ """
+ var v: C? = null
+
+ interface C<caret>
+ """.trimIndent(),
+ """
+ var v: CNew? = null
+
+ interface CNew<caret>
+ """.trimIndent(),
+ "C",
+ "CNew",
+ {
+ myFixture.type("New")
+ }
+ )
+ }
+
+ fun testRenameLocalVar() {
+ doTestRename(
+ """
+ fun foo() {
+ var v<caret> = 0
+ v++
+ }
+ """.trimIndent(),
+ """
+ fun foo() {
+ var vNew<caret> = 0
+ vNew++
+ }
+ """.trimIndent(),
+ "v",
+ "vNew",
+ {
+ myFixture.type("New")
+ }
+ )
+ }
+
+ fun testRenameComponentVar() {
+ doTestRename(
+ """
+ data class Pair<T1, T2>(val t1: T1, val t2: T2)
+
+ fun f(): Pair<String, Int> = Pair("a", 1)
+
+ fun g() {
+ val (a, b<caret>) = f()
+ b.hashCode()
+ }
+ """.trimIndent(),
+ """
+ data class Pair<T1, T2>(val t1: T1, val t2: T2)
+
+ fun f(): Pair<String, Int> = Pair("a", 1)
+
+ fun g() {
+ val (a, b1<caret>) = f()
+ b1.hashCode()
+ }
+ """.trimIndent(),
+ "b",
+ "b1",
+ {
+ myFixture.type("1")
+ }
+ )
+ }
+
+ fun testRenameLoopVar() {
+ doTestRename(
+ """
+ fun f(list: List<String>) {
+ for (s<caret> in list) {
+ s.hashCode()
+ }
+ }
+ """.trimIndent(),
+ """
+ fun f(list: List<String>) {
+ for (s1<caret> in list) {
+ s1.hashCode()
+ }
+ }
+ """.trimIndent(),
+ "s",
+ "s1",
+ {
+ myFixture.type("1")
+ }
+ )
+ }
+
+ fun testRenameParameter() {
+ doTestRename(
+ """
+ fun foo(p<caret>: String) {
+ p.hashCode()
+ }
+ """.trimIndent(),
+ """
+ fun foo(pNew<caret>: String) {
+ pNew.hashCode()
+ }
+ """.trimIndent(),
+ "p",
+ "pNew",
+ {
+ myFixture.type("New")
+ }
+ )
+ }
+
+ fun testRenameParametersInOverrides() {
+ doTestRename(
+ """
+ interface I {
+ fun foo(p<caret>: String)
+ }
+
+ class C : I {
+ override fun foo(p: String) {
+ p.hashCode()
+ }
+ }
+ """.trimIndent(),
+ """
+ interface I {
+ fun foo(pNew<caret>: String)
+ }
+
+ class C : I {
+ override fun foo(pNew: String) {
+ pNew.hashCode()
+ }
+ }
+ """.trimIndent(),
+ "p",
+ "pNew",
+ {
+ myFixture.type("New")
+ }
+ )
+ }
+
+ fun testAddPrimaryConstructorParameter() {
+ ignoreErrorsAfter = true
+ doTestChangeSignature(
+ """
+ class C(private val x: String, y: Int<caret>)
+
+ fun foo() {
+ val c = C("a", 1)
+ }
+ """.trimIndent(),
+ """
+ class C(private val x: String, y: Int, z: Any<caret>)
+
+ fun foo() {
+ val c = C("a", 1, default0)
+ }
+ """.trimIndent(),
+ "usages",
+ { myFixture.type(", z: Any") },
+ expectedPresentation = """
+ Old:
+ 'C'
+ '('
+ LineBreak('', true)
+ Group:
+ 'x'
+ ': '
+ 'String'
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'y'
+ ': '
+ 'Int'
+ LineBreak('', false)
+ ')'
+ New:
+ 'C'
+ '('
+ LineBreak('', true)
+ Group:
+ 'x'
+ ': '
+ 'String'
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'y'
+ ': '
+ 'Int'
+ ','
+ LineBreak(' ', true)
+ Group (added):
+ 'z'
+ ': '
+ 'Any'
+ LineBreak('', false)
+ ')'
+ """.trimIndent()
+ )
+ }
+
+ fun testAddSecondaryConstructorParameter() {
+ ignoreErrorsAfter = true
+ doTestChangeSignature(
+ """
+ class C {
+ constructor(x: String<caret>)
+ }
+
+ fun foo() {
+ val c = C("a")
+ }
+ """.trimIndent(),
+ """
+ class C {
+ constructor(x: String, y: Int<caret>)
+ }
+
+ fun foo() {
+ val c = C("a", default0)
+ }
+ """.trimIndent(),
+ "usages",
+ { myFixture.type(", y: Int") },
+ expectedPresentation = """
+ Old:
+ 'constructor'
+ '('
+ LineBreak('', true)
+ Group:
+ 'x'
+ ': '
+ 'String'
+ LineBreak('', false)
+ ')'
+ New:
+ 'constructor'
+ '('
+ LineBreak('', true)
+ Group:
+ 'x'
+ ': '
+ 'String'
+ ','
+ LineBreak(' ', true)
+ Group (added):
+ 'y'
+ ': '
+ 'Int'
+ LineBreak('', false)
+ ')'
+ """.trimIndent()
+ )
+ }
+
+ fun testAddReceiver() {
+ doTestChangeSignature(
+ """
+ interface I {
+ fun <caret>foo()
+ }
+
+ class C : I {
+ override fun foo() {
+ }
+ }
+ """.trimIndent(),
+ """
+ interface I {
+ fun Int.<caret>foo()
+ }
+
+ class C : I {
+ override fun Int.foo() {
+ }
+ }
+ """.trimIndent(),
+ "usages",
+ { myFixture.type("Int.") },
+ expectedPresentation = """
+ Old:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', false)
+ ')'
+ New:
+ 'fun '
+ 'Int.' (added)
+ 'foo'
+ '('
+ LineBreak('', false)
+ ')'
+ """.trimIndent()
+ )
+ }
+
+ fun testAddReceiverAndParameter() {
+ ignoreErrorsAfter = true
+ doTestChangeSignature(
+ """
+ fun <caret>foo() {
+ }
+
+ fun bar() {
+ foo()
+ }
+ """.trimIndent(),
+ """
+ fun Int.foo(o: Any<caret>) {
+ }
+
+ fun bar() {
+ default0.foo(default1)
+ }
+ """.trimIndent(),
+ "usages",
+ { myFixture.type("Int.") },
+ { repeat("foo(".length) { myFixture.performEditorAction(IdeActions.ACTION_EDITOR_MOVE_CARET_RIGHT) } },
+ { myFixture.type("o: Any") }
+ )
+ }
+
+ fun testRemoveReceiver() {
+ doTestChangeSignature(
+ """
+ fun <caret>Int.foo() {
+ }
+
+ fun bar() {
+ 1.foo()
+ }
+ """.trimIndent(),
+ """
+ fun <caret>foo() {
+ }
+
+ fun bar() {
+ foo()
+ }
+ """.trimIndent(),
+ "usages",
+ {
+ repeat(4) { myFixture.performEditorAction(IdeActions.ACTION_EDITOR_DELETE) }
+ }
+ )
+ }
+
+ fun testChangeReceiverType() {
+ doTestChangeSignature(
+ """
+ interface I {
+ fun <caret>Int.foo()
+ }
+
+ class C : I {
+ override fun Int.foo() {
+ }
+ }
+
+ fun I.f() {
+ 1.foo()
+ }
+ """.trimIndent(),
+ """
+ interface I {
+ fun Any<caret>.foo()
+ }
+
+ class C : I {
+ override fun Any.foo() {
+ }
+ }
+
+ fun I.f() {
+ 1.foo()
+ }
+ """.trimIndent(),
+ "implementations",
+ {
+ repeat("Int".length) { myFixture.performEditorAction(IdeActions.ACTION_EDITOR_DELETE) }
+ myFixture.type("Any")
+ },
+ expectedPresentation = """
+ Old:
+ 'fun '
+ 'Int' (modified)
+ '.'
+ 'foo'
+ '('
+ LineBreak('', false)
+ ')'
+ New:
+ 'fun '
+ 'Any' (modified)
+ '.'
+ 'foo'
+ '('
+ LineBreak('', false)
+ ')'
+ """.trimIndent()
+ )
+ }
+
+ fun testChangeReceiverTypeAndRemoveParameter() {
+ doTestChangeSignature(
+ """
+ fun <caret>Int.foo(p: Any) {}
+
+ fun bar() {
+ 1.foo("a")
+ }
+ """.trimIndent(),
+ """
+ fun Any.foo() {}
+
+ fun bar() {
+ 1.foo()
+ }
+ """.trimIndent(),
+ "usages",
+ {
+ repeat("Int".length) { myFixture.performEditorAction(IdeActions.ACTION_EDITOR_DELETE) }
+ myFixture.type("Any")
+ },
+ {
+ editor.caretModel.moveToOffset(editor.caretModel.offset + ".foo(".length)
+ repeat("p: Any".length) { myFixture.performEditorAction(IdeActions.ACTION_EDITOR_DELETE) }
+ }
+ )
+ }
+
+ fun testAddVarargParameter() {
+ doTestChangeSignature(
+ """
+ interface I {
+ fun foo(p: Int<caret>)
+ }
+
+ class C : I {
+ override fun foo(p: Int) {
+ }
+ }
+ """.trimIndent(),
+ """
+ interface I {
+ fun foo(p: Int, vararg s: String<caret>)
+ }
+
+ class C : I {
+ override fun foo(p: Int, vararg s: String) {
+ }
+ }
+ """.trimIndent(),
+ "usages",
+ { myFixture.type(", vararg s: String") },
+ expectedPresentation = """
+ Old:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group:
+ 'p'
+ ': '
+ 'Int'
+ LineBreak('', false)
+ ')'
+ New:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group:
+ 'p'
+ ': '
+ 'Int'
+ ','
+ LineBreak(' ', true)
+ Group (added):
+ 'vararg'
+ ' '
+ 's'
+ ': '
+ 'String'
+ LineBreak('', false)
+ ')'
+ """.trimIndent()
+ )
+ }
+
+ //TODO
+/*
+ fun testAddVarargModifier() {
+ doTestChangeSignature(
+ """
+ interface I {
+ fun foo(<caret>p: Int)
+ }
+
+ class C : I {
+ override fun foo(p: Int) {
+ }
+ }
+ """.trimIndent(),
+ """
+ interface I {
+ fun foo(vararg <caret>p: Int)
+ }
+
+ class C : I {
+ override fun foo(vararg p: Int) {
+ }
+ }
+ """.trimIndent(),
+ { myFixture.type("vararg ") },
+ expectedPresentation = """
+ Old:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group:
+ 'p'
+ ': '
+ 'Int'
+ LineBreak('', false)
+ ')'
+ New:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group:
+ 'vararg' (added)
+ ' '
+ 'p'
+ ': '
+ 'Int'
+ LineBreak('', false)
+ ')'
+ """.trimIndent()
+ )
+ }
+
+ fun testRemoveVarargModifier() {
+ doTestChangeSignature(
+ """
+ interface I {
+ fun foo(<caret>vararg p: Int)
+ }
+
+ class C : I {
+ override fun foo(vararg p: Int) {
+ }
+ }
+ """.trimIndent(),
+ """
+ interface I {
+ fun foo(<caret>p: Int)
+ }
+
+ class C : I {
+ override fun foo(p: Int) {
+ }
+ }
+ """.trimIndent(),
+ {
+ deleteStringAtCaret("vararg ")
+ },
+ expectedPresentation = """
+ Old:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group:
+ 'vararg' (removed)
+ ' '
+ 'p'
+ ': '
+ 'Int'
+ LineBreak('', false)
+ ')'
+ New:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group:
+ 'p'
+ ': '
+ 'Int'
+ LineBreak('', false)
+ ')'
+ """.trimIndent()
+ )
+ }
+*/
+
+ fun testSwapConstructorParameters() {
+ doTestChangeSignature(
+ """
+ class C(
+ p1: Int,
+ p2: String<caret>
+ )
+
+ fun foo() {
+ C(1, "")
+ }
+ """.trimIndent(),
+ """
+ class C(
+ p2: String,
+ p1: Int
+ )
+
+ fun foo() {
+ C("", 1)
+ }
+ """.trimIndent(),
+ "usages",
+ {
+ myFixture.performEditorAction(IdeActions.ACTION_MOVE_STATEMENT_UP_ACTION)
+ }
+ )
+ }
+
+ fun testChangeParameterTypeOfVirtualExtensionMethod() {
+ doTestChangeSignature(
+ """
+ abstract class Base {
+ protected abstract fun Int.foo(p: <caret>String)
+
+ fun bar() {
+ 1.foo("a")
+ }
+ }
+
+ class Derived : Base() {
+ override fun Int.foo(p: String) {
+ }
+ }
+ """.trimIndent(),
+ """
+ abstract class Base {
+ protected abstract fun Int.foo(p: <caret>Any)
+
+ fun bar() {
+ 1.foo("a")
+ }
+ }
+
+ class Derived : Base() {
+ override fun Int.foo(p: Any) {
+ }
+ }
+ """.trimIndent(),
+ "implementations",
+ {
+ replaceTextAtCaret("String", "Any")
+ }
+ )
+ }
+
+ fun testAddParameterToVirtualExtensionMethod() {
+ ignoreErrorsAfter = true
+ doTestChangeSignature(
+ """
+ abstract class Base {
+ protected abstract fun Int.foo(p: String<caret>)
+
+ fun bar() {
+ 1.foo("a")
+ }
+ }
+
+ class Derived : Base() {
+ override fun Int.foo(p: String) {
+ }
+ }
+ """.trimIndent(),
+ """
+ abstract class Base {
+ protected abstract fun Int.foo(p: String, p1: Int<caret>)
+
+ fun bar() {
+ 1.foo("a", default0)
+ }
+ }
+
+ class Derived : Base() {
+ override fun Int.foo(p: String, p1: Int) {
+ }
+ }
+ """.trimIndent(),
+ "usages",
+ {
+ myFixture.type(", p1: Int")
+ }
+ )
+ }
+
+ fun testAddParameterWithFullyQualifiedType() {
+ doTestChangeSignature(
+ """
+ interface I {
+ fun foo(<caret>)
+ }
+
+ class C : I {
+ override fun foo() {
+ }
+ }
+ """.trimIndent(),
+ """
+ import java.io.InputStream
+
+ interface I {
+ fun foo(p: java.io.InputStream)
+ }
+
+ class C : I {
+ override fun foo(p: InputStream) {
+ }
+ }
+ """.trimIndent(),
+ "usages",
+ { myFixture.type("p: java.io.InputStream") }
+ )
+ }
+
+ fun testAddParameterWithDefaultValue() {
+ doTestChangeSignature(
+ """
+ interface I {
+ fun foo(p1: Int<caret>)
+ }
+
+ class C : I {
+ override fun foo(p1: Int) {
+ }
+ }
+
+ fun f(i: I) {
+ i.foo(1)
+ }
+ """.trimIndent(),
+ """
+ interface I {
+ fun foo(p1: Int, p2: Int = 10<caret>)
+ }
+
+ class C : I {
+ override fun foo(p1: Int, p2: Int) {
+ }
+ }
+
+ fun f(i: I) {
+ i.foo(1)
+ }
+ """.trimIndent(),
+ "usages",
+ {
+ myFixture.type(", p2: Int = 10")
+ },
+ expectedPresentation = """
+ Old:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group:
+ 'p1'
+ ': '
+ 'Int'
+ LineBreak('', false)
+ ')'
+ New:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group:
+ 'p1'
+ ': '
+ 'Int'
+ ','
+ LineBreak(' ', true)
+ Group (added):
+ 'p2'
+ ': '
+ 'Int'
+ ' = '
+ '10'
+ LineBreak('', false)
+ ')'
+ """.trimIndent()
+ )
+ }
+
+ fun testReorderParameterWithDefaultValue() {
+ doTestChangeSignature(
+ """
+ interface I {
+ fun foo(<caret>p1: Int, p2: Int = 10)
+ }
+
+ class C : I {
+ override fun foo(p1: Int, p2: Int) {
+ }
+ }
+
+ fun f(i: I) {
+ i.foo(2)
+ }
+ """.trimIndent(),
+ """
+ interface I {
+ fun foo(p2: Int = 10, <caret>p1: Int)
+ }
+
+ class C : I {
+ override fun foo(p2: Int, p1: Int) {
+ }
+ }
+
+ fun f(i: I) {
+ i.foo(p1 = 2)
+ }
+ """.trimIndent(),
+ "usages",
+ {
+ myFixture.performEditorAction(IdeActions.MOVE_ELEMENT_RIGHT)
+ },
+ expectedPresentation = """
+ Old:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group (moved):
+ 'p1'
+ ': '
+ 'Int'
+ ','
+ LineBreak(' ', true)
+ Group:
+ 'p2'
+ ': '
+ 'Int'
+ ' = '
+ '10'
+ LineBreak('', false)
+ ')'
+ New:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', true)
+ Group:
+ 'p2'
+ ': '
+ 'Int'
+ ' = '
+ '10'
+ ','
+ LineBreak(' ', true)
+ Group (moved):
+ 'p1'
+ ': '
+ 'Int'
+ LineBreak('', false)
+ ')'
+ """.trimIndent()
+ )
+ }
+
+ fun testReplaceTypeWithItsAlias() {
+ doTestChangeSignature(
+ """
+ typealias StringToUnit = (String) -> Unit
+
+ interface I {
+ fun foo(): <caret>(String) -> Unit
+ }
+
+ class C : I {
+ override fun foo(): (String) -> Unit {
+ throw UnsupportedOperationException()
+ }
+ }
+ """.trimIndent(),
+ """
+ typealias StringToUnit = (String) -> Unit
+
+ interface I {
+ fun foo(): <caret>StringToUnit
+ }
+
+ class C : I {
+ override fun foo(): StringToUnit {
+ throw UnsupportedOperationException()
+ }
+ }
+ """.trimIndent(),
+ "implementations",
+ {
+ replaceTextAtCaret("(String) -> Unit", "StringToUnit")
+ },
+ expectedPresentation = """
+ Old:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', false)
+ ')'
+ ': '
+ '(String) -> Unit' (modified)
+ New:
+ 'fun '
+ 'foo'
+ '('
+ LineBreak('', false)
+ ')'
+ ': '
+ 'StringToUnit' (modified)
+ """.trimIndent()
+ )
+ }
+
+ private fun addImport(fqName: String) {
+ (file as KtFile).importList!!.add(KtPsiFactory(project).createImportDirective(ImportPath.fromString(fqName)))
+ }
+
+ private fun removeImport(fqName: String) {
+ (file as KtFile).importList!!.imports.first { it.importedFqName?.asString() == fqName }.delete()
+ }
+}
diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringTest.kt.193 b/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringTest.kt.193
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/suggested/KotlinSuggestedRefactoringTest.kt.193
diff --git a/j2k/tests/org/jetbrains/kotlin/j2k/AbstractJavaToKotlinConverterForWebDemoTest.kt b/j2k/tests/org/jetbrains/kotlin/j2k/AbstractJavaToKotlinConverterForWebDemoTest.kt
index 44f9706..af20c5f 100644
--- a/j2k/tests/org/jetbrains/kotlin/j2k/AbstractJavaToKotlinConverterForWebDemoTest.kt
+++ b/j2k/tests/org/jetbrains/kotlin/j2k/AbstractJavaToKotlinConverterForWebDemoTest.kt
@@ -1,137 +1,134 @@
-/*
- * Copyright 2010-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 org.jetbrains.kotlin.j2k
-
-import com.intellij.codeInsight.ContainerProvider
-import com.intellij.codeInsight.NullableNotNullManager
-import com.intellij.codeInsight.NullableNotNullManagerImpl
-import com.intellij.codeInsight.runner.JavaMainMethodProvider
-import com.intellij.core.CoreApplicationEnvironment
-import com.intellij.core.JavaCoreApplicationEnvironment
-import com.intellij.core.JavaCoreProjectEnvironment
-import com.intellij.lang.MetaLanguage
-import com.intellij.lang.jvm.facade.JvmElementProvider
-import com.intellij.openapi.extensions.Extensions
-import com.intellij.openapi.extensions.ExtensionsArea
-import com.intellij.openapi.fileTypes.FileTypeExtensionPoint
-import com.intellij.openapi.util.Disposer
-import com.intellij.openapi.util.io.FileUtil
-import com.intellij.psi.*
-import com.intellij.psi.augment.PsiAugmentProvider
-import com.intellij.psi.augment.TypeAnnotationModifier
-import com.intellij.psi.compiled.ClassFileDecompilers
-import com.intellij.psi.impl.JavaClassSupersImpl
-import com.intellij.psi.impl.PsiTreeChangePreprocessor
-import com.intellij.psi.meta.MetaDataContributor
-import com.intellij.psi.stubs.BinaryFileStubBuilders
-import com.intellij.psi.util.JavaClassSupers
-import junit.framework.TestCase
-import org.jetbrains.kotlin.utils.PathUtil
-import java.io.File
-import java.net.URLClassLoader
-
-abstract class AbstractJavaToKotlinConverterForWebDemoTest : TestCase() {
- val DISPOSABLE = Disposer.newDisposable()
-
- fun doTest(javaPath: String) {
- try {
- val fileContents = FileUtil.loadFile(File(javaPath), true)
- val javaCoreEnvironment: JavaCoreProjectEnvironment = setUpJavaCoreEnvironment()
- translateToKotlin(fileContents, javaCoreEnvironment.project)
- }
- finally {
- Disposer.dispose(DISPOSABLE)
- }
- }
-
- fun setUpJavaCoreEnvironment(): JavaCoreProjectEnvironment {
- // FIXME: There is no `Extensions.cleanRootArea` in 193 platform
- // Extensions.cleanRootArea(DISPOSABLE)
- val area = Extensions.getRootArea()
-
- registerExtensionPoints(area)
-
- val applicationEnvironment = JavaCoreApplicationEnvironment(DISPOSABLE)
- val javaCoreEnvironment = object : JavaCoreProjectEnvironment(DISPOSABLE, applicationEnvironment) {
- override fun preregisterServices() {
- val projectArea = Extensions.getArea(project)
- CoreApplicationEnvironment.registerExtensionPoint(projectArea, PsiTreeChangePreprocessor.EP_NAME, PsiTreeChangePreprocessor::class.java)
- CoreApplicationEnvironment.registerExtensionPoint(projectArea, PsiElementFinder.EP_NAME, PsiElementFinder::class.java)
- CoreApplicationEnvironment.registerExtensionPoint(projectArea, JvmElementProvider.EP_NAME, JvmElementProvider::class.java)
- }
- }
-
- javaCoreEnvironment.project.registerService(NullableNotNullManager::class.java, object : NullableNotNullManagerImpl(javaCoreEnvironment.project) {
- override fun isNullable(owner: PsiModifierListOwner, checkBases: Boolean) = !isNotNull(owner, checkBases)
- override fun isNotNull(owner: PsiModifierListOwner, checkBases: Boolean) = true
- override fun hasHardcodedContracts(element: PsiElement): Boolean = false
- override fun getNullables() = emptyList<String>()
- override fun setNullables(vararg p0: String) = Unit
- override fun getNotNulls() = emptyList<String>()
- override fun setNotNulls(vararg p0: String) = Unit
- override fun getDefaultNullable() = ""
- override fun setDefaultNullable(defaultNullable: String) = Unit
- override fun getDefaultNotNull() = ""
- override fun setDefaultNotNull(p0: String) = Unit
- override fun setInstrumentedNotNulls(p0: List<String>) = Unit
- override fun getInstrumentedNotNulls() = emptyList<String>()
- })
-
- applicationEnvironment.application.registerService(JavaClassSupers::class.java, JavaClassSupersImpl::class.java)
-
- for (root in PathUtil.getJdkClassesRootsFromCurrentJre()) {
- javaCoreEnvironment.addJarToClassPath(root)
- }
- val annotations: File? = findAnnotations()
- if (annotations != null && annotations.exists()) {
- javaCoreEnvironment.addJarToClassPath(annotations)
- }
- return javaCoreEnvironment
- }
-
- private fun registerExtensionPoints(area: ExtensionsArea) {
- CoreApplicationEnvironment.registerExtensionPoint(area, BinaryFileStubBuilders.EP_NAME, FileTypeExtensionPoint::class.java)
- CoreApplicationEnvironment.registerExtensionPoint(area, FileContextProvider.EP_NAME, FileContextProvider::class.java)
-
- CoreApplicationEnvironment.registerExtensionPoint(area, MetaDataContributor.EP_NAME, MetaDataContributor::class.java)
- CoreApplicationEnvironment.registerExtensionPoint(area, PsiAugmentProvider.EP_NAME, PsiAugmentProvider::class.java)
- CoreApplicationEnvironment.registerExtensionPoint(area, JavaMainMethodProvider.EP_NAME, JavaMainMethodProvider::class.java)
-
- CoreApplicationEnvironment.registerExtensionPoint(area, ContainerProvider.EP_NAME, ContainerProvider::class.java)
- CoreApplicationEnvironment.registerExtensionPoint(area, ClassFileDecompilers.EP_NAME, ClassFileDecompilers.Decompiler::class.java)
-
- CoreApplicationEnvironment.registerExtensionPoint(area, TypeAnnotationModifier.EP_NAME, TypeAnnotationModifier::class.java)
- CoreApplicationEnvironment.registerExtensionPoint(area, MetaLanguage.EP_NAME, MetaLanguage::class.java)
- CoreApplicationEnvironment.registerExtensionPoint(area, JavaModuleSystem.EP_NAME, JavaModuleSystem::class.java)
- }
-
- fun findAnnotations(): File? {
- var classLoader = JavaToKotlinTranslator::class.java.classLoader
- while (classLoader != null) {
- val loader = classLoader
- if (loader is URLClassLoader) {
- for (url in loader.urLs) {
- if ("file" == url.protocol && url.file!!.endsWith("/annotations.jar")) {
- return File(url.file!!)
- }
- }
- }
- classLoader = classLoader.parent
- }
- return null
- }
-}
+/*
+ * Copyright 2010-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 org.jetbrains.kotlin.j2k
+
+import com.intellij.codeInsight.ContainerProvider
+import com.intellij.codeInsight.NullableNotNullManager
+import com.intellij.codeInsight.NullableNotNullManagerImpl
+import com.intellij.codeInsight.runner.JavaMainMethodProvider
+import com.intellij.core.CoreApplicationEnvironment
+import com.intellij.core.JavaCoreApplicationEnvironment
+import com.intellij.core.JavaCoreProjectEnvironment
+import com.intellij.lang.MetaLanguage
+import com.intellij.lang.jvm.facade.JvmElementProvider
+import com.intellij.openapi.extensions.Extensions
+import com.intellij.openapi.extensions.ExtensionsArea
+import com.intellij.openapi.util.Disposer
+import com.intellij.openapi.util.io.FileUtil
+import com.intellij.psi.*
+import com.intellij.psi.augment.PsiAugmentProvider
+import com.intellij.psi.augment.TypeAnnotationModifier
+import com.intellij.psi.compiled.ClassFileDecompilers
+import com.intellij.psi.impl.JavaClassSupersImpl
+import com.intellij.psi.impl.PsiTreeChangePreprocessor
+import com.intellij.psi.meta.MetaDataContributor
+import com.intellij.psi.util.JavaClassSupers
+import junit.framework.TestCase
+import org.jetbrains.kotlin.utils.PathUtil
+import java.io.File
+import java.net.URLClassLoader
+
+abstract class AbstractJavaToKotlinConverterForWebDemoTest : TestCase() {
+ val DISPOSABLE = Disposer.newDisposable()
+
+ fun doTest(javaPath: String) {
+ try {
+ val fileContents = FileUtil.loadFile(File(javaPath), true)
+ val javaCoreEnvironment: JavaCoreProjectEnvironment = setUpJavaCoreEnvironment()
+ translateToKotlin(fileContents, javaCoreEnvironment.project)
+ }
+ finally {
+ Disposer.dispose(DISPOSABLE)
+ }
+ }
+
+ fun setUpJavaCoreEnvironment(): JavaCoreProjectEnvironment {
+ // FIXME: There is no `Extensions.cleanRootArea` in 193 platform
+ // Extensions.cleanRootArea(DISPOSABLE)
+ val area = Extensions.getRootArea()
+
+ registerExtensionPoints(area)
+
+ val applicationEnvironment = JavaCoreApplicationEnvironment(DISPOSABLE)
+ val javaCoreEnvironment = object : JavaCoreProjectEnvironment(DISPOSABLE, applicationEnvironment) {
+ override fun preregisterServices() {
+ val projectArea = Extensions.getArea(project)
+ CoreApplicationEnvironment.registerExtensionPoint(projectArea, PsiTreeChangePreprocessor.EP_NAME, PsiTreeChangePreprocessor::class.java)
+ CoreApplicationEnvironment.registerExtensionPoint(projectArea, PsiElementFinder.EP_NAME, PsiElementFinder::class.java)
+ CoreApplicationEnvironment.registerExtensionPoint(projectArea, JvmElementProvider.EP_NAME, JvmElementProvider::class.java)
+ }
+ }
+
+ javaCoreEnvironment.project.registerService(NullableNotNullManager::class.java, object : NullableNotNullManagerImpl(javaCoreEnvironment.project) {
+ override fun isNullable(owner: PsiModifierListOwner, checkBases: Boolean) = !isNotNull(owner, checkBases)
+ override fun isNotNull(owner: PsiModifierListOwner, checkBases: Boolean) = true
+ override fun hasHardcodedContracts(element: PsiElement): Boolean = false
+ override fun getNullables() = emptyList<String>()
+ override fun setNullables(vararg p0: String) = Unit
+ override fun getNotNulls() = emptyList<String>()
+ override fun setNotNulls(vararg p0: String) = Unit
+ override fun getDefaultNullable() = ""
+ override fun setDefaultNullable(defaultNullable: String) = Unit
+ override fun getDefaultNotNull() = ""
+ override fun setDefaultNotNull(p0: String) = Unit
+ override fun setInstrumentedNotNulls(p0: List<String>) = Unit
+ override fun getInstrumentedNotNulls() = emptyList<String>()
+ })
+
+ applicationEnvironment.application.registerService(JavaClassSupers::class.java, JavaClassSupersImpl::class.java)
+
+ for (root in PathUtil.getJdkClassesRootsFromCurrentJre()) {
+ javaCoreEnvironment.addJarToClassPath(root)
+ }
+ val annotations: File? = findAnnotations()
+ if (annotations != null && annotations.exists()) {
+ javaCoreEnvironment.addJarToClassPath(annotations)
+ }
+ return javaCoreEnvironment
+ }
+
+ private fun registerExtensionPoints(area: ExtensionsArea) {
+ CoreApplicationEnvironment.registerExtensionPoint(area, FileContextProvider.EP_NAME, FileContextProvider::class.java)
+
+ CoreApplicationEnvironment.registerExtensionPoint(area, MetaDataContributor.EP_NAME, MetaDataContributor::class.java)
+ CoreApplicationEnvironment.registerExtensionPoint(area, PsiAugmentProvider.EP_NAME, PsiAugmentProvider::class.java)
+ CoreApplicationEnvironment.registerExtensionPoint(area, JavaMainMethodProvider.EP_NAME, JavaMainMethodProvider::class.java)
+
+ CoreApplicationEnvironment.registerExtensionPoint(area, ContainerProvider.EP_NAME, ContainerProvider::class.java)
+ CoreApplicationEnvironment.registerExtensionPoint(area, ClassFileDecompilers.EP_NAME, ClassFileDecompilers.Decompiler::class.java)
+
+ CoreApplicationEnvironment.registerExtensionPoint(area, TypeAnnotationModifier.EP_NAME, TypeAnnotationModifier::class.java)
+ CoreApplicationEnvironment.registerExtensionPoint(area, MetaLanguage.EP_NAME, MetaLanguage::class.java)
+ CoreApplicationEnvironment.registerExtensionPoint(area, JavaModuleSystem.EP_NAME, JavaModuleSystem::class.java)
+ }
+
+ fun findAnnotations(): File? {
+ var classLoader = JavaToKotlinTranslator::class.java.classLoader
+ while (classLoader != null) {
+ val loader = classLoader
+ if (loader is URLClassLoader) {
+ for (url in loader.urLs) {
+ if ("file" == url.protocol && url.file!!.endsWith("/annotations.jar")) {
+ return File(url.file!!)
+ }
+ }
+ }
+ classLoader = classLoader.parent
+ }
+ return null
+ }
+}
diff --git a/j2k/tests/org/jetbrains/kotlin/j2k/AbstractJavaToKotlinConverterForWebDemoTest.kt.193 b/j2k/tests/org/jetbrains/kotlin/j2k/AbstractJavaToKotlinConverterForWebDemoTest.kt.193
new file mode 100644
index 0000000..7d73186
--- /dev/null
+++ b/j2k/tests/org/jetbrains/kotlin/j2k/AbstractJavaToKotlinConverterForWebDemoTest.kt.193
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2010-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 org.jetbrains.kotlin.j2k
+
+import com.intellij.codeInsight.ContainerProvider
+import com.intellij.codeInsight.NullableNotNullManager
+import com.intellij.codeInsight.NullableNotNullManagerImpl
+import com.intellij.codeInsight.runner.JavaMainMethodProvider
+import com.intellij.core.CoreApplicationEnvironment
+import com.intellij.core.JavaCoreApplicationEnvironment
+import com.intellij.core.JavaCoreProjectEnvironment
+import com.intellij.lang.MetaLanguage
+import com.intellij.lang.jvm.facade.JvmElementProvider
+import com.intellij.openapi.extensions.Extensions
+import com.intellij.openapi.extensions.ExtensionsArea
+import com.intellij.openapi.fileTypes.FileTypeExtensionPoint
+import com.intellij.openapi.util.Disposer
+import com.intellij.openapi.util.io.FileUtil
+import com.intellij.psi.*
+import com.intellij.psi.augment.PsiAugmentProvider
+import com.intellij.psi.augment.TypeAnnotationModifier
+import com.intellij.psi.compiled.ClassFileDecompilers
+import com.intellij.psi.impl.JavaClassSupersImpl
+import com.intellij.psi.impl.PsiTreeChangePreprocessor
+import com.intellij.psi.meta.MetaDataContributor
+import com.intellij.psi.stubs.BinaryFileStubBuilders
+import com.intellij.psi.util.JavaClassSupers
+import junit.framework.TestCase
+import org.jetbrains.kotlin.utils.PathUtil
+import java.io.File
+import java.net.URLClassLoader
+
+abstract class AbstractJavaToKotlinConverterForWebDemoTest : TestCase() {
+ val DISPOSABLE = Disposer.newDisposable()
+
+ fun doTest(javaPath: String) {
+ try {
+ val fileContents = FileUtil.loadFile(File(javaPath), true)
+ val javaCoreEnvironment: JavaCoreProjectEnvironment = setUpJavaCoreEnvironment()
+ translateToKotlin(fileContents, javaCoreEnvironment.project)
+ }
+ finally {
+ Disposer.dispose(DISPOSABLE)
+ }
+ }
+
+ fun setUpJavaCoreEnvironment(): JavaCoreProjectEnvironment {
+ // FIXME: There is no `Extensions.cleanRootArea` in 193 platform
+ // Extensions.cleanRootArea(DISPOSABLE)
+ val area = Extensions.getRootArea()
+
+ registerExtensionPoints(area)
+
+ val applicationEnvironment = JavaCoreApplicationEnvironment(DISPOSABLE)
+ val javaCoreEnvironment = object : JavaCoreProjectEnvironment(DISPOSABLE, applicationEnvironment) {
+ override fun preregisterServices() {
+ val projectArea = Extensions.getArea(project)
+ CoreApplicationEnvironment.registerExtensionPoint(projectArea, PsiTreeChangePreprocessor.EP_NAME, PsiTreeChangePreprocessor::class.java)
+ CoreApplicationEnvironment.registerExtensionPoint(projectArea, PsiElementFinder.EP_NAME, PsiElementFinder::class.java)
+ CoreApplicationEnvironment.registerExtensionPoint(projectArea, JvmElementProvider.EP_NAME, JvmElementProvider::class.java)
+ }
+ }
+
+ javaCoreEnvironment.project.registerService(NullableNotNullManager::class.java, object : NullableNotNullManagerImpl(javaCoreEnvironment.project) {
+ override fun isNullable(owner: PsiModifierListOwner, checkBases: Boolean) = !isNotNull(owner, checkBases)
+ override fun isNotNull(owner: PsiModifierListOwner, checkBases: Boolean) = true
+ override fun hasHardcodedContracts(element: PsiElement): Boolean = false
+ override fun getNullables() = emptyList<String>()
+ override fun setNullables(vararg p0: String) = Unit
+ override fun getNotNulls() = emptyList<String>()
+ override fun setNotNulls(vararg p0: String) = Unit
+ override fun getDefaultNullable() = ""
+ override fun setDefaultNullable(defaultNullable: String) = Unit
+ override fun getDefaultNotNull() = ""
+ override fun setDefaultNotNull(p0: String) = Unit
+ override fun setInstrumentedNotNulls(p0: List<String>) = Unit
+ override fun getInstrumentedNotNulls() = emptyList<String>()
+ })
+
+ applicationEnvironment.application.registerService(JavaClassSupers::class.java, JavaClassSupersImpl::class.java)
+
+ for (root in PathUtil.getJdkClassesRootsFromCurrentJre()) {
+ javaCoreEnvironment.addJarToClassPath(root)
+ }
+ val annotations: File? = findAnnotations()
+ if (annotations != null && annotations.exists()) {
+ javaCoreEnvironment.addJarToClassPath(annotations)
+ }
+ return javaCoreEnvironment
+ }
+
+ private fun registerExtensionPoints(area: ExtensionsArea) {
+ CoreApplicationEnvironment.registerExtensionPoint(area, BinaryFileStubBuilders.EP_NAME, FileTypeExtensionPoint::class.java)
+ CoreApplicationEnvironment.registerExtensionPoint(area, FileContextProvider.EP_NAME, FileContextProvider::class.java)
+
+ CoreApplicationEnvironment.registerExtensionPoint(area, MetaDataContributor.EP_NAME, MetaDataContributor::class.java)
+ CoreApplicationEnvironment.registerExtensionPoint(area, PsiAugmentProvider.EP_NAME, PsiAugmentProvider::class.java)
+ CoreApplicationEnvironment.registerExtensionPoint(area, JavaMainMethodProvider.EP_NAME, JavaMainMethodProvider::class.java)
+
+ CoreApplicationEnvironment.registerExtensionPoint(area, ContainerProvider.EP_NAME, ContainerProvider::class.java)
+ CoreApplicationEnvironment.registerExtensionPoint(area, ClassFileDecompilers.EP_NAME, ClassFileDecompilers.Decompiler::class.java)
+
+ CoreApplicationEnvironment.registerExtensionPoint(area, TypeAnnotationModifier.EP_NAME, TypeAnnotationModifier::class.java)
+ CoreApplicationEnvironment.registerExtensionPoint(area, MetaLanguage.EP_NAME, MetaLanguage::class.java)
+ CoreApplicationEnvironment.registerExtensionPoint(area, JavaModuleSystem.EP_NAME, JavaModuleSystem::class.java)
+ }
+
+ fun findAnnotations(): File? {
+ var classLoader = JavaToKotlinTranslator::class.java.classLoader
+ while (classLoader != null) {
+ val loader = classLoader
+ if (loader is URLClassLoader) {
+ for (url in loader.urLs) {
+ if ("file" == url.protocol && url.file!!.endsWith("/annotations.jar")) {
+ return File(url.file!!)
+ }
+ }
+ }
+ classLoader = classLoader.parent
+ }
+ return null
+ }
+}
diff --git a/tests/mute-platform.csv b/tests/mute-platform.csv
index 2b1d017..a18bc9e 100644
--- a/tests/mute-platform.csv
+++ b/tests/mute-platform.csv
@@ -1,141 +1,228 @@
-Test key, Issue, State (optional: MUTE or FAIL)
-org.jetbrains.kotlin.checkers.JavaAgainstKotlinBinariesCheckerTestGenerated.testClassObjects, ERROR: Access to tree elements not allowed.
-org.jetbrains.kotlin.checkers.JavaAgainstKotlinBinariesCheckerTestGenerated.testUsingKotlinPackageDeclarations, ERROR: Access to tree elements not allowed.
-org.jetbrains.kotlin.findUsages.KotlinFindUsagesWithLibraryTestGenerated.KotlinLibrary.testLibraryClassUsages, KT-34542, FAIL
-org.jetbrains.kotlin.findUsages.KotlinFindUsagesWithLibraryTestGenerated.KotlinLibrary.testLibraryNestedClassUsages, KT-34542, FAIL
-org.jetbrains.kotlin.findUsages.KotlinFindUsagesWithLibraryTestGenerated.KotlinLibrary.testLibraryObjectUsages, KT-34542, FAIL
-org.jetbrains.kotlin.gradle.GradleMultiplatformWizardTest.testMobileShared, IDEA-225878
-org.jetbrains.kotlin.gradle.GradleMultiplatformWizardTest.testNative, IDEA-225878
-org.jetbrains.kotlin.gradle.GradleMultiplatformWizardTest.testShared, IDEA-225878
-org.jetbrains.kotlin.gradle.GradleMultiplatformWizardTest.testSharedWithQualifiedName, IDEA-225878
-org.jetbrains.kotlin.gradle.ImportAndCheckHighlighting.testMultiplatformLibrary[1: Gradle-4.9, KotlinGradlePlugin-latest stable], KT-35631
-org.jetbrains.kotlin.gradle.ImportAndCheckHighlighting.testMultiplatformLibrary[3: Gradle-5.6.4, KotlinGradlePlugin-latest stable], KT-35631
-org.jetbrains.kotlin.gradle.MultiplatformProjectImportingTest.simpleAndroidAppWithCommonModule, KT-35225
-org.jetbrains.kotlin.gradle.MultiplatformProjectImportingTest.testTransitiveImplementWithAndroid, KT-35225
-org.jetbrains.kotlin.idea.caches.resolve.MultiModuleLineMarkerTestGenerated.testKotlinTestAnnotations, No line markers for test run
-org.jetbrains.kotlin.idea.caches.resolve.MultiPlatformHighlightingTestGenerated.testMultifileFacade, KT-34689 invalid light class
-org.jetbrains.kotlin.idea.codeInsight.InspectionTestGenerated.Inspections.testAndroidIllegalIdentifiers_inspectionData_Inspections_test, Unprocessed
-org.jetbrains.kotlin.idea.codeInsight.gradle.GradleFacetImportTest.testAndroidGradleJsDetection, NPE during import
-org.jetbrains.kotlin.idea.codeInsight.gradle.GradleFacetImportTest.testKotlinAndroidPluginDetection, NPE during import
-org.jetbrains.kotlin.idea.codeInsight.gradle.GradleKtsImportTest.testCompositeBuild, FLAKY on windows
-org.jetbrains.kotlin.idea.codeInsight.surroundWith.SurroundWithTestGenerated.If.MoveDeclarationsOut.Order.testTwoClasses, flaky failure
-org.jetbrains.kotlin.idea.codeInsight.surroundWith.SurroundWithTestGenerated.If.MoveDeclarationsOut.Order.testValAndClass, flaky failure
-org.jetbrains.kotlin.idea.codeInsight.surroundWith.SurroundWithTestGenerated.If.MoveDeclarationsOut.Order.testValOrder, flaky failure
-org.jetbrains.kotlin.idea.codeInsight.surroundWith.SurroundWithTestGenerated.If.MoveDeclarationsOut.Val.testValWithTypeWoInitializer, flaky failure
-org.jetbrains.kotlin.idea.codeInsight.surroundWith.SurroundWithTestGenerated.If.MoveDeclarationsOut.Var.testVarWithTypeWoInitializer, Unprocessed
-org.jetbrains.kotlin.idea.completion.test.JvmBasicCompletionTestGenerated.Common.StaticMembers.testJavaStaticMethodsFromImports, KT-32919
-org.jetbrains.kotlin.idea.completion.test.JvmBasicCompletionTestGenerated.Java.BoldOrGrayed.testNonPredictableSmartCast1, KT-32919
-org.jetbrains.kotlin.idea.completion.test.JvmBasicCompletionTestGenerated.Java.BoldOrGrayed.testNonPredictableSmartCast2, KT-32919
-org.jetbrains.kotlin.idea.completion.test.JvmBasicCompletionTestGenerated.Java.BoldOrGrayed.testSyntheticJavaProperties1, KT-32919
-org.jetbrains.kotlin.idea.completion.test.JvmBasicCompletionTestGenerated.Java.BoldOrGrayed.testSyntheticJavaProperties2, KT-32919
-org.jetbrains.kotlin.idea.completion.test.JvmBasicCompletionTestGenerated.Java.SyntheticExtensions.testNullableReceiver, KT-32919
-org.jetbrains.kotlin.idea.completion.test.JvmBasicCompletionTestGenerated.Java.SyntheticExtensions.testSafeCall, KT-32919
-org.jetbrains.kotlin.idea.completion.test.JvmBasicCompletionTestGenerated.Java.SyntheticExtensions.testSmartCast, KT-32919
-org.jetbrains.kotlin.idea.completion.test.JvmBasicCompletionTestGenerated.Java.SyntheticExtensions.testSmartCast2, KT-32919
-org.jetbrains.kotlin.idea.completion.test.JvmBasicCompletionTestGenerated.Java.SyntheticExtensions.testSyntheticExtensions1, KT-32919
-org.jetbrains.kotlin.idea.completion.test.KotlinSourceInJavaCompletionTestGenerated.testMultiFileFacadeMembers, KT-34689
-org.jetbrains.kotlin.idea.decompiler.navigation.NavigateFromJSLibrarySourcesTest.testIcon, Unprocessed
-org.jetbrains.kotlin.idea.decompiler.navigation.NavigateFromLibrarySourcesTest.testBuiltinClass, KT-34542
-org.jetbrains.kotlin.idea.decompiler.navigation.NavigateFromLibrarySourcesTest.testJdkClass, KT-34542
-org.jetbrains.kotlin.idea.decompiler.navigation.NavigateFromLibrarySourcesTest.testLightClassForLibrarySource, KT-34542
-org.jetbrains.kotlin.idea.decompiler.navigation.NavigateFromLibrarySourcesTest.testOurKotlinClass, KT-34542
-org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testClassObject, KT-34542, FAIL
-org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testConstructor, KT-34542, FAIL
-org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testEnum, KT-34542, FAIL
-org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testExtensionFunction, KT-34542, FAIL
-org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testExtensionProperty, KT-34542, FAIL
-org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testGenericFunctionWithExplicitlyDeclaredTypeArguments, KT-34542, FAIL
-org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testGenericFunctionWithInferredTypeArguments, KT-34542, FAIL
-org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testGlobalFunction, KT-34542, FAIL
-org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testGlobalProperty, KT-34542, FAIL
-org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testNamedObject, KT-34542, FAIL
-org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testOverloadedFunWithTypeParam, KT-34542, FAIL
-org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testProperty, KT-34542, FAIL
-org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testSameNameInDifferentSources, KT-34542, FAIL
-org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testTypeAlias, KT-34542, FAIL
-org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testTypeWithSameShortName, KT-34542, FAIL
-org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testClassObject, KT-34542, FAIL
-org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testConstructor, KT-34542, FAIL
-org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testEnum, KT-34542, FAIL
-org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testExtensionFunction, KT-34542, FAIL
-org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testExtensionProperty, KT-34542, FAIL
-org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testGenericFunctionWithExplicitlyDeclaredTypeArguments, KT-34542, FAIL
-org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testGenericFunctionWithInferredTypeArguments, KT-34542, FAIL
-org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testGlobalFunction, KT-34542, FAIL
-org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testGlobalProperty, KT-34542, FAIL
-org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testNamedObject, KT-34542, FAIL
-org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testOverloadedFunWithTypeParam, KT-34542, FAIL
-org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testProperty, KT-34542, FAIL
-org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testSameNameInDifferentSources, KT-34542, FAIL
-org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testTypeAlias, KT-34542, FAIL
-org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testTypeWithSameShortName, KT-34542, FAIL
-org.jetbrains.kotlin.idea.editor.MultiLineStringIndentTestGenerated.Spaces.testDontAddMarginCharWhenMultilineWithoutMargins, KT-34566
-org.jetbrains.kotlin.idea.editor.MultiLineStringIndentTestGenerated.Spaces.testDontAddTrimCallWhenAlreadyMultilineFirstLine, KT-34566
-org.jetbrains.kotlin.idea.editor.MultiLineStringIndentTestGenerated.Spaces.testEnterBeforeMarginChar, KT-34566
-org.jetbrains.kotlin.idea.editor.MultiLineStringIndentTestGenerated.Spaces.testEnterInsideTextMargin, KT-34566
-org.jetbrains.kotlin.idea.editor.MultiLineStringIndentTestGenerated.Spaces.testInsertCustomMarginInLineStart, KT-34566
-org.jetbrains.kotlin.idea.editor.MultiLineStringIndentTestGenerated.WithTabs.Tabs2.testEnterInsideText, KT-34566
-org.jetbrains.kotlin.idea.editor.MultiLineStringIndentTestGenerated.WithTabs.Tabs4.testEnterInsideText, KT-34566
-org.jetbrains.kotlin.idea.filters.KotlinExceptionFilterTestGenerated.testInlineFunCallInLibrary, Unprocessed
-org.jetbrains.kotlin.idea.filters.KotlinExceptionFilterTestGenerated.testInlineFunInnerClassFromLibrary, Unprocessed
-org.jetbrains.kotlin.idea.inspections.CoroutineNonBlockingContextDetectionTest.testCoroutineContextCheck, KT-34659
-org.jetbrains.kotlin.idea.inspections.CoroutineNonBlockingContextDetectionTest.testDispatchersTypeDetection, KT-34659
-org.jetbrains.kotlin.idea.inspections.CoroutineNonBlockingContextDetectionTest.testLambdaReceiverType, KT-34659
-org.jetbrains.kotlin.idea.inspections.CoroutineNonBlockingContextDetectionTest.testNestedFunctionsInsideSuspendLambda, KT-34659
-org.jetbrains.kotlin.idea.inspections.CoroutineNonBlockingContextDetectionTest.testSimpleCoroutineScope, KT-34659
-org.jetbrains.kotlin.idea.inspections.LocalInspectionTestGenerated.RedundantRequireNotNullCall.testUsedAsExpression, KT-34672, FAIL
-org.jetbrains.kotlin.idea.inspections.LocalInspectionTestGenerated.RedundantRequireNotNullCall.testUsedAsExpression2, KT-34672, FAIL
-org.jetbrains.kotlin.idea.inspections.LocalInspectionTestGenerated.RedundantRequireNotNullCall.testUsedAsExpression3, KT-34672, FAIL
-org.jetbrains.kotlin.idea.intentions.IntentionTestGenerated.ConvertFunctionTypeParameterToReceiver.testNonFirstParameterPrimaryConstructor, Flaky failure on ConvertFunctionTypeParameterToReceiver rerun
-org.jetbrains.kotlin.idea.intentions.IntentionTestGenerated.ConvertFunctionTypeParameterToReceiver.testNonFirstParameterSecondaryConstructor, Flaky failure on ConvertFunctionTypeParameterToReceiver rerun
-org.jetbrains.kotlin.idea.intentions.IntentionTestGenerated.ConvertSealedClassToEnum.testInstancesAndMembers, Enum reorder
-org.jetbrains.kotlin.idea.intentions.IntentionTestGenerated.ConvertSealedClassToEnum.testInstancesOnly, Generated entries reordered
-org.jetbrains.kotlin.idea.intentions.IntentionTestGenerated.ConvertSealedClassToEnum.testWithNonObjectInheritors, Enum reorder
-org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testBlankLineBetween, KT-34408
-org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testLongInit, KT-34408
-org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testLongInit2, KT-34408
-org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testPropertyWithAnnotation, KT-34408
-org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testSimpleInit, KT-34408
-org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testSimpleInit2, KT-34408
-org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testSimpleInitWithBackticks, KT-34408
-org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testSimpleInitWithBackticks2, KT-34408
-org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testSimpleInitWithBackticks3, KT-34408
-org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testSimpleInitWithComments, KT-34408
-org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testSimpleInitWithComments2, KT-34408
-org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testSimpleInitWithSemicolons, KT-34408
-org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testSimpleInitWithSemicolons2, KT-34408
-org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testSimpleInitWithSemicolons3, KT-34408
-org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testSimpleInitWithType, KT-34408
-org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testSimpleInitWithType2, KT-34408
-org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.NestedIfs.testBlockBody, KT-34408
-org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.RemoveBraces.testFunctionWithOneLineReturn, KT-34408
-org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.RemoveBraces.testIf, KT-34408
-org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.RemoveBraces.testNotSingleLineStatement, KT-34408
-org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.RemoveBraces.testWhenEntry, KT-34408
-org.jetbrains.kotlin.idea.navigation.KotlinGotoImplementationMultiModuleTestGenerated.testExpectClassSuperclassFun, Flaky failure
-org.jetbrains.kotlin.idea.parameterInfo.ParameterInfoTestGenerated.WithLib1.testUseJavaFromLib, KT-34542, FAIL
-org.jetbrains.kotlin.idea.parameterInfo.ParameterInfoTestGenerated.WithLib2.testUseJavaSAMFromLib, KT-34542, FAIL
-org.jetbrains.kotlin.idea.parameterInfo.ParameterInfoTestGenerated.WithLib3.testUseJavaSAMFromLib, KT-34542, FAIL
-org.jetbrains.kotlin.idea.quickfix.QuickFixMultiFileTestGenerated.ChangeSignature.Jk.testJkKeepValOnParameterTypeChange, Unprocessed
-org.jetbrains.kotlin.idea.quickfix.QuickFixMultiModuleTestGenerated.Other.testConvertActualSealedClassToEnum, Enum reorder
-org.jetbrains.kotlin.idea.quickfix.QuickFixMultiModuleTestGenerated.Other.testConvertExpectSealedClassToEnum, Enum reorder
-org.jetbrains.kotlin.idea.refactoring.inline.InlineTestGenerated.Function.ExpressionBody.testMultipleInExpression, Unstable order of usages
-org.jetbrains.kotlin.idea.refactoring.introduce.ExtractionTestGenerated.IntroduceJavaParameter.testJavaMethodOverridingKotlinFunctionWithUsages, Unprocessed
-org.jetbrains.kotlin.idea.refactoring.move.MoveTestGenerated.testJava_moveClass_moveInnerToTop_moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda_MoveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda, final modifier added
-org.jetbrains.kotlin.idea.refactoring.move.MoveTestGenerated.testJava_moveClass_moveInnerToTop_moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstance_MoveNestedClassToTopLevelInTheSamePackageAndAddOuterInstance, final modifier added
-org.jetbrains.kotlin.idea.refactoring.move.MoveTestGenerated.testKotlin_moveTopLevelDeclarations_moveFunctionToPackage_MoveFunctionToPackage, Broken in 0dc7c37b62f0cfdfb57ee41a808137196c45a9f5
-org.jetbrains.kotlin.idea.refactoring.pullUp.PullUpTestGenerated.K2K.testAccidentalOverrides, Unprocessed
-org.jetbrains.kotlin.idea.refactoring.rename.RenameTestGenerated.testOverloadsWithSameOrigin_OverloadsWithSameOrigin, Bad imports after rename
-org.jetbrains.kotlin.idea.refactoring.rename.RenameTestGenerated.testRenameKotlinMultifileFacadeClassWithJvmNameByRef_RenameKotlinMultifileFacadeClassWithJvmName, KT-34689
-org.jetbrains.kotlin.idea.repl.IdeReplCompletionTestGenerated.testBuiltInMember, KT-34825
-org.jetbrains.kotlin.idea.repl.IdeReplCompletionTestGenerated.testDefinedClass, KT-34825
-org.jetbrains.kotlin.idea.repl.IdeReplCompletionTestGenerated.testDefinedClassMember, KT-34825
-org.jetbrains.kotlin.idea.repl.IdeReplCompletionTestGenerated.testDefinedExtension, KT-34825
-org.jetbrains.kotlin.idea.repl.IdeReplCompletionTestGenerated.testFunctions, KT-34825
-org.jetbrains.kotlin.idea.repl.IdeReplCompletionTestGenerated.testStdlib, KT-34825
-org.jetbrains.kotlin.idea.repl.IdeReplCompletionTestGenerated.testVariables, KT-34825
-org.jetbrains.kotlin.idea.resolve.ReferenceResolveInLibrarySourcesTestGenerated.testInLibrarySource, KT-34542, FAIL
-org.jetbrains.kotlin.idea.resolve.ReferenceResolveInLibrarySourcesTestGenerated.testToFunParameter, KT-34542, FAIL
-org.jetbrains.kotlin.idea.resolve.ReferenceResolveInLibrarySourcesTestGenerated.testToLocalFun, KT-34542, FAIL
-org.jetbrains.kotlin.idea.script.ScriptConfigurationHighlightingTestGenerated.Highlighting.testCustomJavaHome, No Java
-org.jetbrains.uast.test.kotlin.KotlinUastReferencesTest.`test original getter is visible when reference is under renaming`, Extensions API changed
\ No newline at end of file
+Test key, Issue, State (optional: MUTE or FAIL)
+org.jetbrains.kotlin.asJava.classes.UltraLightClassLoadingTestGenerated.testEnums, value and valueOf methods
+org.jetbrains.kotlin.asJava.classes.UltraLightClassSanityTestGenerated.CompilationErrors.testEnumNameOverride, value and valueOf methods
+org.jetbrains.kotlin.asJava.classes.UltraLightClassSanityTestGenerated.testAnnotatedParameterInEnumConstructor, value and valueOf methods
+org.jetbrains.kotlin.asJava.classes.UltraLightClassSanityTestGenerated.testDeprecatedEnumEntry, value and valueOf methods
+org.jetbrains.kotlin.checkers.JavaAgainstKotlinBinariesCheckerTestGenerated.testClassObjects, ERROR: Access to tree elements not allowed.
+org.jetbrains.kotlin.checkers.JavaAgainstKotlinBinariesCheckerTestGenerated.testUsingKotlinPackageDeclarations, ERROR: Access to tree elements not allowed.
+org.jetbrains.kotlin.checkers.JavaAgainstKotlinSourceCheckerWithoutUltraLightTestGenerated.JavaAgainstKotlin.testEnumAutoGeneratedMethods, NPE in light classes with enum
+org.jetbrains.kotlin.findUsages.KotlinFindUsagesWithLibraryTestGenerated.KotlinLibrary.testLibraryClassUsages, KT-34542, FAIL
+org.jetbrains.kotlin.findUsages.KotlinFindUsagesWithLibraryTestGenerated.KotlinLibrary.testLibraryNestedClassUsages, KT-34542, FAIL
+org.jetbrains.kotlin.findUsages.KotlinFindUsagesWithLibraryTestGenerated.KotlinLibrary.testLibraryObjectUsages, KT-34542, FAIL
+org.jetbrains.kotlin.gradle.GradleMultiplatformWizardTest.testMobileShared, IDEA-225878
+org.jetbrains.kotlin.gradle.GradleMultiplatformWizardTest.testNative, IDEA-225878
+org.jetbrains.kotlin.gradle.GradleMultiplatformWizardTest.testShared, IDEA-225878
+org.jetbrains.kotlin.gradle.GradleMultiplatformWizardTest.testSharedWithQualifiedName, IDEA-225878
+org.jetbrains.kotlin.gradle.HierarchicalMultiplatformProjectImportingTest.testJvmWithJavaOnHMPP[1: Gradle-4.9, KotlinGradlePlugin-latest stable], No module dependency found
+org.jetbrains.kotlin.gradle.HierarchicalMultiplatformProjectImportingTest.testJvmWithJavaOnHMPP[3: Gradle-5.6.4, KotlinGradlePlugin-latest stable], No module dependency found
+org.jetbrains.kotlin.gradle.ImportAndCheckHighlighting.testMultiplatformLibrary[1: Gradle-4.9, KotlinGradlePlugin-latest stable], KT-35631
+org.jetbrains.kotlin.gradle.ImportAndCheckHighlighting.testMultiplatformLibrary[3: Gradle-5.6.4, KotlinGradlePlugin-latest stable], KT-35631
+org.jetbrains.kotlin.gradle.MultiplatformProjectImportingTest.simpleAndroidAppWithCommonModule, KT-35225
+org.jetbrains.kotlin.gradle.MultiplatformProjectImportingTest.testDependenciesReachableViaImpl[0: Gradle-4.9, KotlinGradlePlugin-minimal], Gradle Tests in 201
+org.jetbrains.kotlin.gradle.MultiplatformProjectImportingTest.testDependenciesReachableViaImpl[1: Gradle-4.9, KotlinGradlePlugin-latest stable], Gradle Tests in 201
+org.jetbrains.kotlin.gradle.MultiplatformProjectImportingTest.testDependenciesReachableViaImpl[2: Gradle-5.6.4, KotlinGradlePlugin-minimal], Gradle Tests in 201
+org.jetbrains.kotlin.gradle.MultiplatformProjectImportingTest.testDependenciesReachableViaImpl[3: Gradle-5.6.4, KotlinGradlePlugin-latest stable], Gradle Tests in 201
+org.jetbrains.kotlin.gradle.MultiplatformProjectImportingTest.testTransitiveImplementWithAndroid, KT-35225
+org.jetbrains.kotlin.gradle.MultiplatformProjectImportingTest.testTransitiveImplementWithNonDefaultConfig[0: Gradle-4.9, KotlinGradlePlugin-minimal], Gradle Tests in 201
+org.jetbrains.kotlin.gradle.MultiplatformProjectImportingTest.testTransitiveImplementWithNonDefaultConfig[1: Gradle-4.9, KotlinGradlePlugin-latest stable], Gradle Tests in 201
+org.jetbrains.kotlin.gradle.MultiplatformProjectImportingTest.testTransitiveImplementWithNonDefaultConfig[2: Gradle-5.6.4, KotlinGradlePlugin-minimal], Gradle Tests in 201
+org.jetbrains.kotlin.gradle.MultiplatformProjectImportingTest.testTransitiveImplementWithNonDefaultConfig[3: Gradle-5.6.4, KotlinGradlePlugin-latest stable], Gradle Tests in 201
+org.jetbrains.kotlin.gradle.MultiplatformProjectImportingTest.testTransitiveImplement[0: Gradle-4.9, KotlinGradlePlugin-minimal], Gradle Tests in 201
+org.jetbrains.kotlin.gradle.MultiplatformProjectImportingTest.testTransitiveImplement[1: Gradle-4.9, KotlinGradlePlugin-latest stable], Gradle Tests in 201
+org.jetbrains.kotlin.gradle.MultiplatformProjectImportingTest.testTransitiveImplement[2: Gradle-5.6.4, KotlinGradlePlugin-minimal], Gradle Tests in 201
+org.jetbrains.kotlin.gradle.MultiplatformProjectImportingTest.testTransitiveImplement[3: Gradle-5.6.4, KotlinGradlePlugin-latest stable], Gradle Tests in 201
+org.jetbrains.kotlin.gradle.NewMultiplatformProjectImportingTest.testAndroidDependencyOnMPP[1: Gradle-4.9, KotlinGradlePlugin-latest stable], Gradle Tests in 201
+org.jetbrains.kotlin.gradle.NewMultiplatformProjectImportingTest.testAndroidDependencyOnMPP[1: Gradle-4.9, KotlinGradlePlugin-latest stable], Gradle Tests in 201
+org.jetbrains.kotlin.gradle.NewMultiplatformProjectImportingTest.testAndroidDependencyOnMPP[3: Gradle-5.6.4, KotlinGradlePlugin-latest stable], Gradle Tests in 201
+org.jetbrains.kotlin.gradle.NewMultiplatformProjectImportingTest.testAndroidDependencyOnMPP[3: Gradle-5.6.4, KotlinGradlePlugin-latest stable], Gradle Tests in 201
+org.jetbrains.kotlin.gradle.NewMultiplatformProjectImportingTest.testDependencyOnRoot[1: Gradle-4.9, KotlinGradlePlugin-latest stable], Gradle Tests in 201
+org.jetbrains.kotlin.gradle.NewMultiplatformProjectImportingTest.testDependencyOnRoot[3: Gradle-5.6.4, KotlinGradlePlugin-latest stable], Gradle Tests in 201
+org.jetbrains.kotlin.gradle.NewMultiplatformProjectImportingTest.testDetectAndroidSources[1: Gradle-4.9, KotlinGradlePlugin-latest stable], Gradle Tests in 201
+org.jetbrains.kotlin.gradle.NewMultiplatformProjectImportingTest.testDetectAndroidSources[1: Gradle-4.9, KotlinGradlePlugin-latest stable], Gradle Tests in 201
+org.jetbrains.kotlin.gradle.NewMultiplatformProjectImportingTest.testDetectAndroidSources[3: Gradle-5.6.4, KotlinGradlePlugin-latest stable], Gradle Tests in 201
+org.jetbrains.kotlin.gradle.NewMultiplatformProjectImportingTest.testDetectAndroidSources[3: Gradle-5.6.4, KotlinGradlePlugin-latest stable], Gradle Tests in 201
+org.jetbrains.kotlin.gradle.NewMultiplatformProjectImportingTest.testImportBeforeBuild[1: Gradle-4.9, KotlinGradlePlugin-latest stable], Gradle Tests in 201
+org.jetbrains.kotlin.gradle.NewMultiplatformProjectImportingTest.testImportBeforeBuild[3: Gradle-5.6.4, KotlinGradlePlugin-latest stable], Gradle Tests in 201
+org.jetbrains.kotlin.gradle.NewMultiplatformProjectImportingTest.testJavaTransitiveOnMPP[1: Gradle-4.9, KotlinGradlePlugin-latest stable], Gradle Tests in 201
+org.jetbrains.kotlin.gradle.NewMultiplatformProjectImportingTest.testJavaTransitiveOnMPP[3: Gradle-5.6.4, KotlinGradlePlugin-latest stable], Gradle Tests in 201
+org.jetbrains.kotlin.gradle.NewMultiplatformProjectImportingTest.testJvmWithJava[1: Gradle-4.9, KotlinGradlePlugin-latest stable], Gradle Tests in 201
+org.jetbrains.kotlin.gradle.NewMultiplatformProjectImportingTest.testJvmWithJava[3: Gradle-5.6.4, KotlinGradlePlugin-latest stable], Gradle Tests in 201
+org.jetbrains.kotlin.gradle.NewMultiplatformProjectImportingTest.testNestedDependencies[1: Gradle-4.9, KotlinGradlePlugin-latest stable], Gradle Tests in 201
+org.jetbrains.kotlin.gradle.NewMultiplatformProjectImportingTest.testNestedDependencies[3: Gradle-5.6.4, KotlinGradlePlugin-latest stable], Gradle Tests in 201
+org.jetbrains.kotlin.gradle.NewMultiplatformProjectImportingTest.testProjectDependency[1: Gradle-4.9, KotlinGradlePlugin-latest stable], Gradle Tests in 201
+org.jetbrains.kotlin.gradle.NewMultiplatformProjectImportingTest.testProjectDependency[3: Gradle-5.6.4, KotlinGradlePlugin-latest stable], Gradle Tests in 201
+org.jetbrains.kotlin.idea.caches.resolve.IdeLightClassTestGenerated.CompilationErrors.testEnumNameOverride, NPE in light classes with enum
+org.jetbrains.kotlin.idea.caches.resolve.IdeLightClassTestGenerated.testAnnotatedParameterInEnumConstructor, NPE in light classes with enum
+org.jetbrains.kotlin.idea.caches.resolve.IdeLightClassTestGenerated.testDeprecatedEnumEntry, NPE in light classes with enum
+org.jetbrains.kotlin.idea.caches.resolve.MultiModuleLineMarkerTestGenerated.testKotlinTestAnnotations, No line markers for test run
+org.jetbrains.kotlin.idea.caches.resolve.MultiPlatformHighlightingTestGenerated.testMultifileFacade, KT-34689 invalid light class
+org.jetbrains.kotlin.idea.codeInsight.InspectionTestGenerated.Inspections.testAndroidIllegalIdentifiers_inspectionData_Inspections_test, Unprocessed
+org.jetbrains.kotlin.idea.codeInsight.gradle.GradleFacetImportTest.testAndroidGradleJsDetection, NPE during import
+org.jetbrains.kotlin.idea.codeInsight.gradle.GradleFacetImportTest.testKotlinAndroidPluginDetection, NPE during import
+org.jetbrains.kotlin.idea.codeInsight.gradle.GradleKtsImportTest.testCompositeBuild, FLAKY on windows
+org.jetbrains.kotlin.idea.codeInsight.surroundWith.SurroundWithTestGenerated.If.MoveDeclarationsOut.Order.testTwoClasses, flaky failure
+org.jetbrains.kotlin.idea.codeInsight.surroundWith.SurroundWithTestGenerated.If.MoveDeclarationsOut.Order.testValAndClass, flaky failure
+org.jetbrains.kotlin.idea.codeInsight.surroundWith.SurroundWithTestGenerated.If.MoveDeclarationsOut.Order.testValOrder, flaky failure
+org.jetbrains.kotlin.idea.codeInsight.surroundWith.SurroundWithTestGenerated.If.MoveDeclarationsOut.Val.testValWithTypeWoInitializer, flaky failure
+org.jetbrains.kotlin.idea.codeInsight.surroundWith.SurroundWithTestGenerated.If.MoveDeclarationsOut.Var.testVarWithTypeWoInitializer, Unprocessed
+org.jetbrains.kotlin.idea.completion.test.JvmBasicCompletionTestGenerated.Common.StaticMembers.testJavaStaticMethodsFromImports, KT-32919
+org.jetbrains.kotlin.idea.completion.test.JvmBasicCompletionTestGenerated.Java.BoldOrGrayed.testNonPredictableSmartCast1, KT-32919
+org.jetbrains.kotlin.idea.completion.test.JvmBasicCompletionTestGenerated.Java.BoldOrGrayed.testNonPredictableSmartCast2, KT-32919
+org.jetbrains.kotlin.idea.completion.test.JvmBasicCompletionTestGenerated.Java.BoldOrGrayed.testSyntheticJavaProperties1, KT-32919
+org.jetbrains.kotlin.idea.completion.test.JvmBasicCompletionTestGenerated.Java.BoldOrGrayed.testSyntheticJavaProperties2, KT-32919
+org.jetbrains.kotlin.idea.completion.test.JvmBasicCompletionTestGenerated.Java.SyntheticExtensions.testNullableReceiver, KT-32919
+org.jetbrains.kotlin.idea.completion.test.JvmBasicCompletionTestGenerated.Java.SyntheticExtensions.testSafeCall, KT-32919
+org.jetbrains.kotlin.idea.completion.test.JvmBasicCompletionTestGenerated.Java.SyntheticExtensions.testSmartCast, KT-32919
+org.jetbrains.kotlin.idea.completion.test.JvmBasicCompletionTestGenerated.Java.SyntheticExtensions.testSmartCast2, KT-32919
+org.jetbrains.kotlin.idea.completion.test.JvmBasicCompletionTestGenerated.Java.SyntheticExtensions.testSyntheticExtensions1, KT-32919
+org.jetbrains.kotlin.idea.completion.test.KotlinSourceInJavaCompletionTestGenerated.testMultiFileFacadeMembers, KT-34689
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateFromJSLibrarySourcesTest.testIcon, Unprocessed
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateFromLibrarySourcesTest.testBuiltinClass, KT-34542
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateFromLibrarySourcesTest.testJdkClass, KT-34542
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateFromLibrarySourcesTest.testLightClassForLibrarySource, KT-34542
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateFromLibrarySourcesTest.testOurKotlinClass, KT-34542
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testClassObject, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testConstructor, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testEnum, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testExtensionFunction, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testExtensionProperty, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testGenericFunctionWithExplicitlyDeclaredTypeArguments, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testGenericFunctionWithInferredTypeArguments, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testGlobalFunction, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testGlobalProperty, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testNamedObject, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testOverloadedFunWithTypeParam, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testProperty, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testSameNameInDifferentSources, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testTypeAlias, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testTypeWithSameShortName, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testClassObject, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testConstructor, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testEnum, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testExtensionFunction, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testExtensionProperty, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testGenericFunctionWithExplicitlyDeclaredTypeArguments, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testGenericFunctionWithInferredTypeArguments, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testGlobalFunction, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testGlobalProperty, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testNamedObject, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testOverloadedFunWithTypeParam, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testProperty, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testSameNameInDifferentSources, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testTypeAlias, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testTypeWithSameShortName, KT-34542, FAIL
+org.jetbrains.kotlin.idea.editor.MultiLineStringIndentTestGenerated.Spaces.testDontAddMarginCharWhenMultilineWithoutMargins, KT-34566
+org.jetbrains.kotlin.idea.editor.MultiLineStringIndentTestGenerated.Spaces.testDontAddTrimCallWhenAlreadyMultilineFirstLine, KT-34566
+org.jetbrains.kotlin.idea.editor.MultiLineStringIndentTestGenerated.Spaces.testEnterBeforeMarginChar, KT-34566
+org.jetbrains.kotlin.idea.editor.MultiLineStringIndentTestGenerated.Spaces.testEnterInsideTextMargin, KT-34566
+org.jetbrains.kotlin.idea.editor.MultiLineStringIndentTestGenerated.Spaces.testInsertCustomMarginInLineStart, KT-34566
+org.jetbrains.kotlin.idea.editor.MultiLineStringIndentTestGenerated.WithTabs.Tabs2.testEnterInsideText, KT-34566
+org.jetbrains.kotlin.idea.editor.MultiLineStringIndentTestGenerated.WithTabs.Tabs4.testEnterInsideText, KT-34566
+org.jetbrains.kotlin.idea.filters.KotlinExceptionFilterTestGenerated.testInlineFunCallInLibrary, Unprocessed
+org.jetbrains.kotlin.idea.filters.KotlinExceptionFilterTestGenerated.testInlineFunInnerClassFromLibrary, Unprocessed
+org.jetbrains.kotlin.idea.inspections.CoroutineNonBlockingContextDetectionTest.testCoroutineContextCheck, KT-34659
+org.jetbrains.kotlin.idea.inspections.CoroutineNonBlockingContextDetectionTest.testDispatchersTypeDetection, KT-34659
+org.jetbrains.kotlin.idea.inspections.CoroutineNonBlockingContextDetectionTest.testLambdaReceiverType, KT-34659
+org.jetbrains.kotlin.idea.inspections.CoroutineNonBlockingContextDetectionTest.testNestedFunctionsInsideSuspendLambda, KT-34659
+org.jetbrains.kotlin.idea.inspections.CoroutineNonBlockingContextDetectionTest.testSimpleCoroutineScope, KT-34659
+org.jetbrains.kotlin.idea.inspections.LocalInspectionTestGenerated.RedundantRequireNotNullCall.testUsedAsExpression, KT-34672, FAIL
+org.jetbrains.kotlin.idea.inspections.LocalInspectionTestGenerated.RedundantRequireNotNullCall.testUsedAsExpression2, KT-34672, FAIL
+org.jetbrains.kotlin.idea.inspections.LocalInspectionTestGenerated.RedundantRequireNotNullCall.testUsedAsExpression3, KT-34672, FAIL
+org.jetbrains.kotlin.idea.intentions.IntentionTestGenerated.ConvertFunctionTypeParameterToReceiver.testNonFirstParameterPrimaryConstructor, Flaky failure on ConvertFunctionTypeParameterToReceiver rerun
+org.jetbrains.kotlin.idea.intentions.IntentionTestGenerated.ConvertFunctionTypeParameterToReceiver.testNonFirstParameterSecondaryConstructor, Flaky failure on ConvertFunctionTypeParameterToReceiver rerun
+org.jetbrains.kotlin.idea.intentions.IntentionTestGenerated.ConvertSealedClassToEnum.testInstancesAndMembers, Enum reorder
+org.jetbrains.kotlin.idea.intentions.IntentionTestGenerated.ConvertSealedClassToEnum.testInstancesOnly, Generated entries reordered
+org.jetbrains.kotlin.idea.intentions.IntentionTestGenerated.ConvertSealedClassToEnum.testWithNonObjectInheritors, Enum reorder
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testBlankLineBetween, KT-34408
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testLongInit, KT-34408
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testLongInit2, KT-34408
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testPropertyWithAnnotation, KT-34408
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testSimpleInit, KT-34408
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testSimpleInit2, KT-34408
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testSimpleInitWithBackticks, KT-34408
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testSimpleInitWithBackticks2, KT-34408
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testSimpleInitWithBackticks3, KT-34408
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testSimpleInitWithComments, KT-34408
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testSimpleInitWithComments2, KT-34408
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testSimpleInitWithSemicolons, KT-34408
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testSimpleInitWithSemicolons2, KT-34408
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testSimpleInitWithSemicolons3, KT-34408
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testSimpleInitWithType, KT-34408
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testSimpleInitWithType2, KT-34408
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.NestedIfs.testBlockBody, KT-34408
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.RemoveBraces.testFunctionWithOneLineReturn, KT-34408
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.RemoveBraces.testIf, KT-34408
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.RemoveBraces.testNotSingleLineStatement, KT-34408
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.RemoveBraces.testWhenEntry, KT-34408
+org.jetbrains.kotlin.idea.navigation.KotlinGotoImplementationMultiModuleTestGenerated.testExpectClassSuperclassFun, Flaky failure
+org.jetbrains.kotlin.idea.parameterInfo.ParameterInfoTestGenerated.WithLib1.testUseJavaFromLib, KT-34542, FAIL
+org.jetbrains.kotlin.idea.parameterInfo.ParameterInfoTestGenerated.WithLib2.testUseJavaSAMFromLib, KT-34542, FAIL
+org.jetbrains.kotlin.idea.parameterInfo.ParameterInfoTestGenerated.WithLib3.testUseJavaSAMFromLib, KT-34542, FAIL
+org.jetbrains.kotlin.idea.quickfix.QuickFixMultiFileTestGenerated.ChangeSignature.Jk.testJkKeepValOnParameterTypeChange, Unprocessed
+org.jetbrains.kotlin.idea.quickfix.QuickFixMultiModuleTestGenerated.AddMissingActualMembers.testClassFunctionWithIncompatibleConstructor, Range must be inside element being annotated
+org.jetbrains.kotlin.idea.quickfix.QuickFixMultiModuleTestGenerated.Other.testConvertActualSealedClassToEnum, Enum reorder
+org.jetbrains.kotlin.idea.quickfix.QuickFixMultiModuleTestGenerated.Other.testConvertExpectSealedClassToEnum, Enum reorder
+org.jetbrains.kotlin.idea.quickfix.QuickFixTestGenerated.CreateFromUsage.CreateSecondaryConstructor.testNoneApplicable, Range must be inside element being annotated
+org.jetbrains.kotlin.idea.quickfix.QuickFixTestGenerated.InsertDelegationCall.testNonApplicableInsertSuper, Range must be inside element being annotated
+org.jetbrains.kotlin.idea.quickfix.QuickFixTestGenerated.InsertDelegationCall.testNonApplicableInsertSuper, Range must be inside element being annotated
+org.jetbrains.kotlin.idea.quickfix.QuickFixTestGenerated.InsertDelegationCall.testNonApplicableInsertThis, Range must be inside element being annotated
+org.jetbrains.kotlin.idea.quickfix.QuickFixTestGenerated.InsertDelegationCall.testNonApplicableInsertThis, Range must be inside element being annotated
+org.jetbrains.kotlin.idea.quickfix.QuickFixTestGenerated.InsertDelegationCall.testNonApplicableOnEmpty, Range must be inside element being annotated
+org.jetbrains.kotlin.idea.quickfix.QuickFixTestGenerated.InsertDelegationCall.testNonApplicableOnEmpty, Range must be inside element being annotated
+org.jetbrains.kotlin.idea.quickfix.QuickFixTestGenerated.InsertDelegationCall.testNonApplicableWithOneConstructor, Range must be inside element being annotated
+org.jetbrains.kotlin.idea.quickfix.QuickFixTestGenerated.InsertDelegationCall.testNonApplicableWithOneConstructor, Range must be inside element being annotated
+org.jetbrains.kotlin.idea.quickfix.QuickFixTestGenerated.InsertDelegationCall.testPrimaryRequiredNoSuper, Range must be inside element being annotated
+org.jetbrains.kotlin.idea.quickfix.QuickFixTestGenerated.InsertDelegationCall.testPrimaryRequiredNoSuper, Range must be inside element being annotated
+org.jetbrains.kotlin.idea.quickfix.QuickFixTestGenerated.InsertDelegationCall.testPrimaryRequiredParameterless, Range must be inside element being annotated
+org.jetbrains.kotlin.idea.quickfix.QuickFixTestGenerated.InsertDelegationCall.testPrimaryRequiredParameterless, Range must be inside element being annotated
+org.jetbrains.kotlin.idea.quickfix.QuickFixTestGenerated.InsertDelegationCall.testPrimaryRequiredWithBody, Range must be inside element being annotated
+org.jetbrains.kotlin.idea.quickfix.QuickFixTestGenerated.InsertDelegationCall.testPrimaryRequiredWithBody, Range must be inside element being annotated
+org.jetbrains.kotlin.idea.quickfix.QuickFixTestGenerated.InsertDelegationCall.testPrimaryRequiredWithParameter, Range must be inside element being annotated
+org.jetbrains.kotlin.idea.quickfix.QuickFixTestGenerated.InsertDelegationCall.testPrimaryRequiredWithParameter, Range must be inside element being annotated
+org.jetbrains.kotlin.idea.refactoring.inline.InlineTestGenerated.Function.ExpressionBody.testMultipleInExpression, Unstable order of usages
+org.jetbrains.kotlin.idea.refactoring.introduce.ExtractionTestGenerated.IntroduceJavaParameter.testJavaMethodOverridingKotlinFunctionWithUsages, Unprocessed
+org.jetbrains.kotlin.idea.refactoring.move.MoveTestGenerated.testJava_moveClass_moveInnerToTop_moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda_MoveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda, final modifier added
+org.jetbrains.kotlin.idea.refactoring.move.MoveTestGenerated.testJava_moveClass_moveInnerToTop_moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstance_MoveNestedClassToTopLevelInTheSamePackageAndAddOuterInstance, final modifier added
+org.jetbrains.kotlin.idea.refactoring.move.MoveTestGenerated.testKotlin_moveTopLevelDeclarations_moveFunctionToPackage_MoveFunctionToPackage, Broken in 0dc7c37b62f0cfdfb57ee41a808137196c45a9f5
+org.jetbrains.kotlin.idea.refactoring.pullUp.PullUpTestGenerated.K2K.testAccidentalOverrides, Unprocessed
+org.jetbrains.kotlin.idea.refactoring.rename.RenameTestGenerated.testJavaEnumValueOf_JavaEnumValueOf, Enums in 201
+org.jetbrains.kotlin.idea.refactoring.rename.RenameTestGenerated.testOverloadsWithSameOrigin_OverloadsWithSameOrigin, Bad imports after rename
+org.jetbrains.kotlin.idea.refactoring.rename.RenameTestGenerated.testRenameKotlinMultifileFacadeClassWithJvmNameByRef_RenameKotlinMultifileFacadeClassWithJvmName, KT-34689
+org.jetbrains.kotlin.idea.refactoring.suggested.KotlinSuggestedRefactoringChangeListenerTest.test1, Additional signature
+org.jetbrains.kotlin.idea.refactoring.suggested.KotlinSuggestedRefactoringChangeListenerTest.testAddImport, Additional signature
+org.jetbrains.kotlin.idea.refactoring.suggested.KotlinSuggestedRefactoringChangeListenerTest.testAddImportWithBlankLineInsertion, Additional signature
+org.jetbrains.kotlin.idea.refactoring.suggested.KotlinSuggestedRefactoringChangeListenerTest.testAddImportWithBlankLinesRemoval, Additional signature
+org.jetbrains.kotlin.idea.refactoring.suggested.KotlinSuggestedRefactoringChangeListenerTest.testCommentTyping, Additional signature
+org.jetbrains.kotlin.idea.repl.IdeReplCompletionTestGenerated.testBuiltInMember, KT-34825
+org.jetbrains.kotlin.idea.repl.IdeReplCompletionTestGenerated.testDefinedClass, KT-34825
+org.jetbrains.kotlin.idea.repl.IdeReplCompletionTestGenerated.testDefinedClassMember, KT-34825
+org.jetbrains.kotlin.idea.repl.IdeReplCompletionTestGenerated.testDefinedExtension, KT-34825
+org.jetbrains.kotlin.idea.repl.IdeReplCompletionTestGenerated.testFunctions, KT-34825
+org.jetbrains.kotlin.idea.repl.IdeReplCompletionTestGenerated.testStdlib, KT-34825
+org.jetbrains.kotlin.idea.repl.IdeReplCompletionTestGenerated.testVariables, KT-34825
+org.jetbrains.kotlin.idea.resolve.FirReferenceResolveTestGenerated.testJavaEnumValueOf, value and valueOf methods
+org.jetbrains.kotlin.idea.resolve.ReferenceResolveInLibrarySourcesTestGenerated.testInLibrarySource, KT-34542, FAIL
+org.jetbrains.kotlin.idea.resolve.ReferenceResolveInLibrarySourcesTestGenerated.testToFunParameter, KT-34542, FAIL
+org.jetbrains.kotlin.idea.resolve.ReferenceResolveInLibrarySourcesTestGenerated.testToLocalFun, KT-34542, FAIL
+org.jetbrains.kotlin.idea.resolve.ReferenceResolveTestGenerated.testJavaEnumValueOf, value and valueOf methods
+org.jetbrains.kotlin.idea.script.ScriptConfigurationHighlightingTestGenerated.Highlighting.testCustomJavaHome, No Java
+org.jetbrains.kotlin.idea.scripting.gradle.GradleScriptInputsWatcherTest.testChangeInsideNonKtsFileInvalidatesOtherFiles, Assert: some script configuration loading tasks should be scheduled
+org.jetbrains.kotlin.idea.scripting.gradle.GradleScriptInputsWatcherTest.testChangeInsideSectionsInvalidatesOtherFiles, Assert: some script configuration loading tasks should be scheduled
+org.jetbrains.kotlin.idea.scripting.gradle.GradleScriptInputsWatcherTest.testChangeOutsideSectionsInvalidatesOtherFiles, Assert: some script configuration loading tasks should be scheduled
+org.jetbrains.kotlin.idea.scripting.gradle.GradleScriptInputsWatcherTest.testConfigurationUpdateAfterProjectClosing, Assert: some script configuration loading tasks should be scheduled
+org.jetbrains.kotlin.idea.scripting.gradle.GradleScriptInputsWatcherTest.testFileAttributesUpdateAfterChangeOutsideSectionsOfOtherFile, Assert: some script configuration loading tasks should be scheduled
+org.jetbrains.kotlin.idea.scripting.gradle.GradleScriptInputsWatcherTest.testLoadedConfigurationWhenExternalFileChanged, Assert: some script configuration loading tasks should be scheduled
+org.jetbrains.kotlin.idea.scripting.gradle.GradleScriptInputsWatcherTest.testTwoFilesChanged, Assert: some script configuration loading tasks should be scheduled
+org.jetbrains.kotlin.jps.build.IncrementalConstantSearchTest.testJavaConstantChangedUsedInKotlin, Incremental compilation in 201
+org.jetbrains.kotlin.jps.build.IncrementalJvmJpsTestGenerated.WithJava.JavaUsedInKotlin.testConstantChanged, Incremental compilation in 201
+org.jetbrains.kotlin.nj2k.NewJavaToKotlinConverterSingleFileTestGenerated.Function.testExternalFunctionalInterface, NJ2K in 201
+org.jetbrains.kotlin.nj2k.NewJavaToKotlinConverterSingleFileTestGenerated.Issues.testKt_19604, NJ2K in 201
+org.jetbrains.kotlin.nj2k.NewJavaToKotlinConverterSingleFileTestGenerated.Issues.testKt_19606, NJ2K in 201
+org.jetbrains.kotlin.nj2k.NewJavaToKotlinConverterSingleFileTestGenerated.Issues.testKt_32702, NJ2K in 201
+org.jetbrains.kotlin.nj2k.NewJavaToKotlinConverterSingleFileTestGenerated.ObjectLiteral.testKt_36149, NJ2K in 201
+org.jetbrains.kotlin.nj2k.NewJavaToKotlinConverterSingleFileTestGenerated.Types.testCapturedWildcardTypeAsLambdaParameter, NJ2K in 201
+org.jetbrains.kotlin.nj2k.NewJavaToKotlinConverterSingleFileTestGenerated.Types.testUnusedCapturedWildcardTypeInSAM, NJ2K in 201
+org.jetbrains.kotlin.search.TodoSearchTest.testTodoCall, Duplicate TODO items
+org.jetbrains.uast.test.kotlin.KotlinUastReferencesTest.`test original getter is visible when reference is under renaming`, Extensions API changed
+org.jetbrains.uast.test.kotlin.SimpleKotlinRenderLogTest.testEnumValueMembers, values and valueOf
+org.jetbrains.uast.test.kotlin.SimpleKotlinRenderLogTest.testEnumValuesConstructors, values and valueOf
\ No newline at end of file
diff --git a/tests/mute-platform.csv.193 b/tests/mute-platform.csv.193
new file mode 100644
index 0000000..dc09cce
--- /dev/null
+++ b/tests/mute-platform.csv.193
@@ -0,0 +1,141 @@
+Test key, Issue, State (optional: MUTE or FAIL)
+org.jetbrains.kotlin.checkers.JavaAgainstKotlinBinariesCheckerTestGenerated.testClassObjects, ERROR: Access to tree elements not allowed.
+org.jetbrains.kotlin.checkers.JavaAgainstKotlinBinariesCheckerTestGenerated.testUsingKotlinPackageDeclarations, ERROR: Access to tree elements not allowed.
+org.jetbrains.kotlin.findUsages.KotlinFindUsagesWithLibraryTestGenerated.KotlinLibrary.testLibraryClassUsages, KT-34542, FAIL
+org.jetbrains.kotlin.findUsages.KotlinFindUsagesWithLibraryTestGenerated.KotlinLibrary.testLibraryNestedClassUsages, KT-34542, FAIL
+org.jetbrains.kotlin.findUsages.KotlinFindUsagesWithLibraryTestGenerated.KotlinLibrary.testLibraryObjectUsages, KT-34542, FAIL
+org.jetbrains.kotlin.gradle.GradleMultiplatformWizardTest.testMobileShared, IDEA-225878
+org.jetbrains.kotlin.gradle.GradleMultiplatformWizardTest.testNative, IDEA-225878
+org.jetbrains.kotlin.gradle.GradleMultiplatformWizardTest.testShared, IDEA-225878
+org.jetbrains.kotlin.gradle.GradleMultiplatformWizardTest.testSharedWithQualifiedName, IDEA-225878
+org.jetbrains.kotlin.gradle.ImportAndCheckHighlighting.testMultiplatformLibrary[1: Gradle-4.9, KotlinGradlePlugin-latest stable], KT-35631
+org.jetbrains.kotlin.gradle.ImportAndCheckHighlighting.testMultiplatformLibrary[3: Gradle-5.6.4, KotlinGradlePlugin-latest stable], KT-35631
+org.jetbrains.kotlin.gradle.MultiplatformProjectImportingTest.simpleAndroidAppWithCommonModule, KT-35225
+org.jetbrains.kotlin.gradle.MultiplatformProjectImportingTest.testTransitiveImplementWithAndroid, KT-35225
+org.jetbrains.kotlin.idea.caches.resolve.MultiModuleLineMarkerTestGenerated.testKotlinTestAnnotations, No line markers for test run
+org.jetbrains.kotlin.idea.caches.resolve.MultiPlatformHighlightingTestGenerated.testMultifileFacade, KT-34689 invalid light class
+org.jetbrains.kotlin.idea.codeInsight.InspectionTestGenerated.Inspections.testAndroidIllegalIdentifiers_inspectionData_Inspections_test, Unprocessed
+org.jetbrains.kotlin.idea.codeInsight.gradle.GradleFacetImportTest.testAndroidGradleJsDetection, NPE during import
+org.jetbrains.kotlin.idea.codeInsight.gradle.GradleFacetImportTest.testKotlinAndroidPluginDetection, NPE during import
+org.jetbrains.kotlin.idea.codeInsight.gradle.GradleKtsImportTest.testCompositeBuild, FLAKY on windows
+org.jetbrains.kotlin.idea.codeInsight.surroundWith.SurroundWithTestGenerated.If.MoveDeclarationsOut.Order.testTwoClasses, flaky failure
+org.jetbrains.kotlin.idea.codeInsight.surroundWith.SurroundWithTestGenerated.If.MoveDeclarationsOut.Order.testValAndClass, flaky failure
+org.jetbrains.kotlin.idea.codeInsight.surroundWith.SurroundWithTestGenerated.If.MoveDeclarationsOut.Order.testValOrder, flaky failure
+org.jetbrains.kotlin.idea.codeInsight.surroundWith.SurroundWithTestGenerated.If.MoveDeclarationsOut.Val.testValWithTypeWoInitializer, flaky failure
+org.jetbrains.kotlin.idea.codeInsight.surroundWith.SurroundWithTestGenerated.If.MoveDeclarationsOut.Var.testVarWithTypeWoInitializer, Unprocessed
+org.jetbrains.kotlin.idea.completion.test.JvmBasicCompletionTestGenerated.Common.StaticMembers.testJavaStaticMethodsFromImports, KT-32919
+org.jetbrains.kotlin.idea.completion.test.JvmBasicCompletionTestGenerated.Java.BoldOrGrayed.testNonPredictableSmartCast1, KT-32919
+org.jetbrains.kotlin.idea.completion.test.JvmBasicCompletionTestGenerated.Java.BoldOrGrayed.testNonPredictableSmartCast2, KT-32919
+org.jetbrains.kotlin.idea.completion.test.JvmBasicCompletionTestGenerated.Java.BoldOrGrayed.testSyntheticJavaProperties1, KT-32919
+org.jetbrains.kotlin.idea.completion.test.JvmBasicCompletionTestGenerated.Java.BoldOrGrayed.testSyntheticJavaProperties2, KT-32919
+org.jetbrains.kotlin.idea.completion.test.JvmBasicCompletionTestGenerated.Java.SyntheticExtensions.testNullableReceiver, KT-32919
+org.jetbrains.kotlin.idea.completion.test.JvmBasicCompletionTestGenerated.Java.SyntheticExtensions.testSafeCall, KT-32919
+org.jetbrains.kotlin.idea.completion.test.JvmBasicCompletionTestGenerated.Java.SyntheticExtensions.testSmartCast, KT-32919
+org.jetbrains.kotlin.idea.completion.test.JvmBasicCompletionTestGenerated.Java.SyntheticExtensions.testSmartCast2, KT-32919
+org.jetbrains.kotlin.idea.completion.test.JvmBasicCompletionTestGenerated.Java.SyntheticExtensions.testSyntheticExtensions1, KT-32919
+org.jetbrains.kotlin.idea.completion.test.KotlinSourceInJavaCompletionTestGenerated.testMultiFileFacadeMembers, KT-34689
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateFromJSLibrarySourcesTest.testIcon, Unprocessed
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateFromLibrarySourcesTest.testBuiltinClass, KT-34542
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateFromLibrarySourcesTest.testJdkClass, KT-34542
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateFromLibrarySourcesTest.testLightClassForLibrarySource, KT-34542
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateFromLibrarySourcesTest.testOurKotlinClass, KT-34542
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testClassObject, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testConstructor, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testEnum, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testExtensionFunction, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testExtensionProperty, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testGenericFunctionWithExplicitlyDeclaredTypeArguments, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testGenericFunctionWithInferredTypeArguments, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testGlobalFunction, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testGlobalProperty, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testNamedObject, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testOverloadedFunWithTypeParam, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testProperty, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testSameNameInDifferentSources, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testTypeAlias, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestGenerated.testTypeWithSameShortName, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testClassObject, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testConstructor, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testEnum, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testExtensionFunction, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testExtensionProperty, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testGenericFunctionWithExplicitlyDeclaredTypeArguments, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testGenericFunctionWithInferredTypeArguments, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testGlobalFunction, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testGlobalProperty, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testNamedObject, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testOverloadedFunWithTypeParam, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testProperty, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testSameNameInDifferentSources, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testTypeAlias, KT-34542, FAIL
+org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToLibrarySourceTestWithJSGenerated.testTypeWithSameShortName, KT-34542, FAIL
+org.jetbrains.kotlin.idea.editor.MultiLineStringIndentTestGenerated.Spaces.testDontAddMarginCharWhenMultilineWithoutMargins, KT-34566
+org.jetbrains.kotlin.idea.editor.MultiLineStringIndentTestGenerated.Spaces.testDontAddTrimCallWhenAlreadyMultilineFirstLine, KT-34566
+org.jetbrains.kotlin.idea.editor.MultiLineStringIndentTestGenerated.Spaces.testEnterBeforeMarginChar, KT-34566
+org.jetbrains.kotlin.idea.editor.MultiLineStringIndentTestGenerated.Spaces.testEnterInsideTextMargin, KT-34566
+org.jetbrains.kotlin.idea.editor.MultiLineStringIndentTestGenerated.Spaces.testInsertCustomMarginInLineStart, KT-34566
+org.jetbrains.kotlin.idea.editor.MultiLineStringIndentTestGenerated.WithTabs.Tabs2.testEnterInsideText, KT-34566
+org.jetbrains.kotlin.idea.editor.MultiLineStringIndentTestGenerated.WithTabs.Tabs4.testEnterInsideText, KT-34566
+org.jetbrains.kotlin.idea.filters.KotlinExceptionFilterTestGenerated.testInlineFunCallInLibrary, Unprocessed
+org.jetbrains.kotlin.idea.filters.KotlinExceptionFilterTestGenerated.testInlineFunInnerClassFromLibrary, Unprocessed
+org.jetbrains.kotlin.idea.inspections.CoroutineNonBlockingContextDetectionTest.testCoroutineContextCheck, KT-34659
+org.jetbrains.kotlin.idea.inspections.CoroutineNonBlockingContextDetectionTest.testDispatchersTypeDetection, KT-34659
+org.jetbrains.kotlin.idea.inspections.CoroutineNonBlockingContextDetectionTest.testLambdaReceiverType, KT-34659
+org.jetbrains.kotlin.idea.inspections.CoroutineNonBlockingContextDetectionTest.testNestedFunctionsInsideSuspendLambda, KT-34659
+org.jetbrains.kotlin.idea.inspections.CoroutineNonBlockingContextDetectionTest.testSimpleCoroutineScope, KT-34659
+org.jetbrains.kotlin.idea.inspections.LocalInspectionTestGenerated.RedundantRequireNotNullCall.testUsedAsExpression, KT-34672, FAIL
+org.jetbrains.kotlin.idea.inspections.LocalInspectionTestGenerated.RedundantRequireNotNullCall.testUsedAsExpression2, KT-34672, FAIL
+org.jetbrains.kotlin.idea.inspections.LocalInspectionTestGenerated.RedundantRequireNotNullCall.testUsedAsExpression3, KT-34672, FAIL
+org.jetbrains.kotlin.idea.intentions.IntentionTestGenerated.ConvertFunctionTypeParameterToReceiver.testNonFirstParameterPrimaryConstructor, Flaky failure on ConvertFunctionTypeParameterToReceiver rerun
+org.jetbrains.kotlin.idea.intentions.IntentionTestGenerated.ConvertFunctionTypeParameterToReceiver.testNonFirstParameterSecondaryConstructor, Flaky failure on ConvertFunctionTypeParameterToReceiver rerun
+org.jetbrains.kotlin.idea.intentions.IntentionTestGenerated.ConvertSealedClassToEnum.testInstancesAndMembers, Enum reorder
+org.jetbrains.kotlin.idea.intentions.IntentionTestGenerated.ConvertSealedClassToEnum.testInstancesOnly, Generated entries reordered
+org.jetbrains.kotlin.idea.intentions.IntentionTestGenerated.ConvertSealedClassToEnum.testWithNonObjectInheritors, Enum reorder
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testBlankLineBetween, KT-34408
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testLongInit, KT-34408
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testLongInit2, KT-34408
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testPropertyWithAnnotation, KT-34408
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testSimpleInit, KT-34408
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testSimpleInit2, KT-34408
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testSimpleInitWithBackticks, KT-34408
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testSimpleInitWithBackticks2, KT-34408
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testSimpleInitWithBackticks3, KT-34408
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testSimpleInitWithComments, KT-34408
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testSimpleInitWithComments2, KT-34408
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testSimpleInitWithSemicolons, KT-34408
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testSimpleInitWithSemicolons2, KT-34408
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testSimpleInitWithSemicolons3, KT-34408
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testSimpleInitWithType, KT-34408
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.DeclarationAndAssignment.testSimpleInitWithType2, KT-34408
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.NestedIfs.testBlockBody, KT-34408
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.RemoveBraces.testFunctionWithOneLineReturn, KT-34408
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.RemoveBraces.testIf, KT-34408
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.RemoveBraces.testNotSingleLineStatement, KT-34408
+org.jetbrains.kotlin.idea.intentions.declarations.JoinLinesTestGenerated.RemoveBraces.testWhenEntry, KT-34408
+org.jetbrains.kotlin.idea.navigation.KotlinGotoImplementationMultiModuleTestGenerated.testExpectClassSuperclassFun, Flaky failure
+org.jetbrains.kotlin.idea.parameterInfo.ParameterInfoTestGenerated.WithLib1.testUseJavaFromLib, KT-34542, FAIL
+org.jetbrains.kotlin.idea.parameterInfo.ParameterInfoTestGenerated.WithLib2.testUseJavaSAMFromLib, KT-34542, FAIL
+org.jetbrains.kotlin.idea.parameterInfo.ParameterInfoTestGenerated.WithLib3.testUseJavaSAMFromLib, KT-34542, FAIL
+org.jetbrains.kotlin.idea.quickfix.QuickFixMultiFileTestGenerated.ChangeSignature.Jk.testJkKeepValOnParameterTypeChange, Unprocessed
+org.jetbrains.kotlin.idea.quickfix.QuickFixMultiModuleTestGenerated.Other.testConvertActualSealedClassToEnum, Enum reorder
+org.jetbrains.kotlin.idea.quickfix.QuickFixMultiModuleTestGenerated.Other.testConvertExpectSealedClassToEnum, Enum reorder
+org.jetbrains.kotlin.idea.refactoring.inline.InlineTestGenerated.Function.ExpressionBody.testMultipleInExpression, Unstable order of usages
+org.jetbrains.kotlin.idea.refactoring.introduce.ExtractionTestGenerated.IntroduceJavaParameter.testJavaMethodOverridingKotlinFunctionWithUsages, Unprocessed
+org.jetbrains.kotlin.idea.refactoring.move.MoveTestGenerated.testJava_moveClass_moveInnerToTop_moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda_MoveNestedClassToTopLevelInTheSamePackageAndAddOuterInstanceWithLambda, final modifier added
+org.jetbrains.kotlin.idea.refactoring.move.MoveTestGenerated.testJava_moveClass_moveInnerToTop_moveNestedClassToTopLevelInTheSamePackageAndAddOuterInstance_MoveNestedClassToTopLevelInTheSamePackageAndAddOuterInstance, final modifier added
+org.jetbrains.kotlin.idea.refactoring.move.MoveTestGenerated.testKotlin_moveTopLevelDeclarations_moveFunctionToPackage_MoveFunctionToPackage, Broken in 0dc7c37b62f0cfdfb57ee41a808137196c45a9f5
+org.jetbrains.kotlin.idea.refactoring.pullUp.PullUpTestGenerated.K2K.testAccidentalOverrides, Unprocessed
+org.jetbrains.kotlin.idea.refactoring.rename.RenameTestGenerated.testOverloadsWithSameOrigin_OverloadsWithSameOrigin, Bad imports after rename
+org.jetbrains.kotlin.idea.refactoring.rename.RenameTestGenerated.testRenameKotlinMultifileFacadeClassWithJvmNameByRef_RenameKotlinMultifileFacadeClassWithJvmName, KT-34689
+org.jetbrains.kotlin.idea.repl.IdeReplCompletionTestGenerated.testBuiltInMember, KT-34825
+org.jetbrains.kotlin.idea.repl.IdeReplCompletionTestGenerated.testDefinedClass, KT-34825
+org.jetbrains.kotlin.idea.repl.IdeReplCompletionTestGenerated.testDefinedClassMember, KT-34825
+org.jetbrains.kotlin.idea.repl.IdeReplCompletionTestGenerated.testDefinedExtension, KT-34825
+org.jetbrains.kotlin.idea.repl.IdeReplCompletionTestGenerated.testFunctions, KT-34825
+org.jetbrains.kotlin.idea.repl.IdeReplCompletionTestGenerated.testStdlib, KT-34825
+org.jetbrains.kotlin.idea.repl.IdeReplCompletionTestGenerated.testVariables, KT-34825
+org.jetbrains.kotlin.idea.resolve.ReferenceResolveInLibrarySourcesTestGenerated.testInLibrarySource, KT-34542, FAIL
+org.jetbrains.kotlin.idea.resolve.ReferenceResolveInLibrarySourcesTestGenerated.testToFunParameter, KT-34542, FAIL
+org.jetbrains.kotlin.idea.resolve.ReferenceResolveInLibrarySourcesTestGenerated.testToLocalFun, KT-34542, FAIL
+org.jetbrains.kotlin.idea.script.ScriptConfigurationHighlightingTestGenerated.Highlighting.testCustomJavaHome, No Java
+org.jetbrains.uast.test.kotlin.KotlinUastReferencesTest.`test original getter is visible when reference is under renaming`, Extensions API changed
\ No newline at end of file