// 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.codeInsight.daemon.impl;

import com.intellij.lang.annotation.Annotator;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.util.ReflectionUtil;
import com.intellij.util.pico.CachingConstructorInjectionComponentAdapter;
import gnu.trove.THashMap;
import org.jetbrains.annotations.NotNull;
import org.picocontainer.PicoContainer;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

abstract class ThreadLocalAnnotatorMap<K, V> {
  private volatile int version;
  @NotNull
  public abstract Collection<V> initialValue(@NotNull K key);

  private static class VersionedMap<K, V> extends THashMap<K, List<V>> {
    private final int version;

    private VersionedMap(int version) {
      this.version = version;
    }
  }

  private final ThreadLocal<VersionedMap<K, V>> CACHE = new ThreadLocal<VersionedMap<K, V>>(){
    @Override
    protected VersionedMap<K, V> initialValue() {
      return new VersionedMap<>(version);
    }
  };

  @SuppressWarnings("unchecked")
  @NotNull
  private List<V> cloneTemplates(@NotNull Collection<? extends V> templates) {
    List<V> result = new ArrayList<>(templates.size());
    PicoContainer container = ApplicationManager.getApplication().getPicoContainer();
    for (V template : templates) {
      Class<? extends V> aClass = (Class<? extends V>)template.getClass();
      V clone;
      // todo in general CachingConstructorInjectionComponentAdapter should be not used at all, but for now disable it only for known cases
      if (Annotator.class.isAssignableFrom(aClass)) {
        clone = ReflectionUtil.newInstance(aClass);
      }
      else {
        clone = (V)new CachingConstructorInjectionComponentAdapter(aClass.getName(), aClass, null, true).getComponentInstance(container);
      }
      result.add(clone);
    }
    return result;
  }

  @NotNull
  public List<V> get(@NotNull K key) {
    VersionedMap<K, V> map = CACHE.get();
    if (version != map.version) {
      CACHE.remove();
      map = CACHE.get();
    }
    List<V> cached = map.get(key);
    if (cached == null) {
      Collection<V> templates = initialValue(key);
      cached = cloneTemplates(templates);
      map.put(key, cached);
    }
    return cached;
  }

  public void clear() {
    version++; //we don't care about atomicity here
  }
}

@@ -646,40 +646,8 @@
 %3E %7B%0A
-  private volatile int version;%0A
   @N
@@ -645,32 +645,32 @@
 V%3E %7B%0A  @NotNull%0A
+
   public abstrac
@@ -730,229 +730,45 @@
 ate 
-static class VersionedMap%3CK, V%3E extends THashMap%3CK, List%3CV%3E%3E %7B%0A    private final int version;%0A%0A    private VersionedMap(int version) %7B%0A      this.version = version;%0A    %7D%0A  %7D%0A%0A  private final ThreadLocal%3CVersionedMap%3CK, V
+final ThreadLocal%3CTHashMap%3CK, List%3CV%3E
 %3E%3E C
@@ -773,20 +773,16 @@
  CACHE =
- new
  ThreadL
@@ -789,147 +789,44 @@
 ocal
-%3CVersionedMap%3CK, V%3E%3E()%7B%0A    @Override%0A    protected VersionedMap%3CK, V%3E initialValue() %7B%0A      return new VersionedMap%3C%3E(version);%0A    %7D%0A  %7D
+.withInitial(() -%3E new THashMap%3C%3E())
 ;%0A%0A 
@@ -1740,25 +1740,27 @@
     
-VersionedMap%3CK, V
+THashMap%3CK, List%3CV%3E
 %3E ma
@@ -1780,95 +1780,8 @@
 ();%0A
-    if (version != map.version) %7B%0A      CACHE.remove();%0A      map = CACHE.get();%0A    %7D%0A
     
@@ -1990,88 +1990,7 @@
 %0A  %7D
-%0A%0A  public void clear() %7B%0A    version++; //we don't care about atomicity here%0A  %7D
 %0A%7D%0A

Remove versioning support in ThreadLocalAnnotatorMap (unused since 165d8f827d)