/*
 * Copyright 2000-2014 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.jetbrains.python.psi.resolve;

import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.vfs.*;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.QualifiedName;
import com.intellij.reference.SoftReference;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author yole
 */
public abstract class PythonPathCache {
  private final Map<QualifiedName, List<SoftReference<PsiElement>>> myCache = ContainerUtil.newConcurrentMap();
  private final Map<String, List<QualifiedName>> myQNameCache = ContainerUtil.newConcurrentMap();

  public void clearCache() {
    myCache.clear();
    myQNameCache.clear();
  }

  /***
   * @return null if nothing found in cache. If path resolves to nothing you get empty list
   */
  @Nullable
  public List<PsiElement> get(@NotNull final QualifiedName qualifiedName) {
    final List<SoftReference<PsiElement>> references = myCache.get(qualifiedName);
    if (references == null) {
      return null;
    }
    final List<PsiElement> result = references.stream().map(r -> r.get()).collect(Collectors.toList());
    if (result.stream().anyMatch(o -> o == null || ! o.isValid())) {
      // Null in list means SoftReference has been collected meaning cache is not valid
      return null;
    }
    return result;
  }

  public void put(QualifiedName qualifiedName, List<PsiElement> results) {
    if (results != null) {
      myCache.put(qualifiedName, new ArrayList<>(results.stream().map(e -> new SoftReference<>(e)).collect(Collectors.toList())));
    }
  }

  @Nullable
  public List<QualifiedName> getNames(VirtualFile vFile) {
    if (vFile == null) {
      return null;
    }
    return myQNameCache.get(vFile.getUrl());
  }

  public void putNames(VirtualFile vFile, List<QualifiedName> qNames) {
    myQNameCache.put(vFile.getUrl(), new ArrayList<>(qNames));
  }

  protected class MyVirtualFileAdapter extends VirtualFileAdapter {
    @Override
    public void fileCreated(@NotNull VirtualFileEvent event) {
      clearCache();
    }

    @Override
    public void fileDeleted(@NotNull VirtualFileEvent event) {
      clearCache();
    }

    @Override
    public void fileMoved(@NotNull VirtualFileMoveEvent event) {
      clearCache();
    }

    @Override
    public void fileCopied(@NotNull VirtualFileCopyEvent event) {
      clearCache();
    }

    @Override
    public void propertyChanged(@NotNull VirtualFilePropertyEvent event) {
      if (event.getPropertyName().equals(VirtualFile.PROP_NAME)) {
        clearCache();
      }
    }
  }
}

@@ -1190,21 +1190,16 @@
 edName, 
-List%3C
 SoftRefe
@@ -1196,32 +1196,37 @@
 , SoftReference%3C
+List%3C
 PsiElement%3E%3E%3E my
@@ -1650,21 +1650,16 @@
   final 
-List%3C
 SoftRefe
@@ -1664,16 +1664,21 @@
 ference%3C
+List%3C
 PsiEleme
@@ -1805,22 +1805,24 @@
 lement%3E 
-result
+elements
  = refer
@@ -1831,79 +1831,52 @@
 ces.
-stream().map(r -%3E r.get()).collect(Collectors.toList());%0A    if (result
+get();%0A    if(elements != null && ! elements
 .str
@@ -1886,47 +1886,35 @@
 ().a
-ny
+ll
 Match(
-o -%3E o == null %7C%7C ! o.
+PsiElement::
 isValid
-()
 )) %7B
@@ -1927,81 +1927,34 @@
  // 
-Null in list means SoftReference has been collected meaning cache is not 
+At least one element is in
 vali
@@ -1991,22 +1991,24 @@
  return 
-result
+elements
 ;%0A  %7D%0A%0A 
@@ -2149,98 +2149,31 @@
 new 
-ArrayList%3C%3E(results.stream().map(e -%3E new SoftReference%3C%3E(e)).collect(Collectors.toList())
+SoftReference%3C%3E(results
 ));%0A

Use soft ref to list instead of list of soft refs to cleanup code * See https://github.com/JetBrains/intellij-community/commit/2b5487ff1a457c519be8f6bb9775c85ffc03c4cf#commitcomment-21133757