mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
make underlying map really immutable to simplify and avoid accidents
This commit is contained in:
@@ -24,6 +24,7 @@ import com.intellij.psi.impl.source.PsiClassReferenceType;
|
|||||||
import com.intellij.psi.util.PsiUtil;
|
import com.intellij.psi.util.PsiUtil;
|
||||||
import com.intellij.psi.util.PsiUtilCore;
|
import com.intellij.psi.util.PsiUtilCore;
|
||||||
import com.intellij.util.ArrayUtil;
|
import com.intellij.util.ArrayUtil;
|
||||||
|
import com.intellij.util.containers.UnmodifiableTHashMap;
|
||||||
import gnu.trove.THashMap;
|
import gnu.trove.THashMap;
|
||||||
import gnu.trove.TObjectHashingStrategy;
|
import gnu.trove.TObjectHashingStrategy;
|
||||||
import org.jetbrains.annotations.NonNls;
|
import org.jetbrains.annotations.NonNls;
|
||||||
@@ -58,21 +59,15 @@ public class PsiSubstitutorImpl implements PsiSubstitutor {
|
|||||||
private final SubstitutionVisitor mySimpleSubstitutionVisitor = new SubstitutionVisitor();
|
private final SubstitutionVisitor mySimpleSubstitutionVisitor = new SubstitutionVisitor();
|
||||||
|
|
||||||
private PsiSubstitutorImpl(@NotNull Map<PsiTypeParameter, PsiType> map) {
|
private PsiSubstitutorImpl(@NotNull Map<PsiTypeParameter, PsiType> map) {
|
||||||
mySubstitutionMap = new THashMap<>(map, PSI_EQUIVALENCE);
|
mySubstitutionMap = map;
|
||||||
}
|
|
||||||
|
|
||||||
private PsiSubstitutorImpl() {
|
|
||||||
mySubstitutionMap = new THashMap<>(2, PSI_EQUIVALENCE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PsiSubstitutorImpl(@NotNull PsiTypeParameter typeParameter, PsiType mapping) {
|
PsiSubstitutorImpl(@NotNull PsiTypeParameter typeParameter, PsiType mapping) {
|
||||||
this();
|
this(Collections.singletonMap(typeParameter, mapping));
|
||||||
mySubstitutionMap.put(typeParameter, mapping);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PsiSubstitutorImpl(@NotNull PsiClass parentClass, PsiType[] mappings) {
|
PsiSubstitutorImpl(@NotNull PsiClass parentClass, PsiType[] mappings) {
|
||||||
this();
|
this(putAllInternal(Collections.emptyMap(), parentClass, mappings));
|
||||||
putAllInternal(parentClass, mappings);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -304,45 +299,45 @@ public class PsiSubstitutorImpl implements PsiSubstitutor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected PsiSubstitutorImpl clone() {
|
protected PsiSubstitutorImpl clone() {
|
||||||
return new PsiSubstitutorImpl(mySubstitutionMap);
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public PsiSubstitutor put(@NotNull PsiTypeParameter typeParameter, PsiType mapping) {
|
public PsiSubstitutor put(@NotNull PsiTypeParameter typeParameter, PsiType mapping) {
|
||||||
PsiSubstitutorImpl ret = clone();
|
|
||||||
if (mapping != null && !mapping.isValid()) {
|
if (mapping != null && !mapping.isValid()) {
|
||||||
LOG.error("Invalid type in substitutor: " + mapping + "; " + mapping.getClass());
|
LOG.error("Invalid type in substitutor: " + mapping + "; " + mapping.getClass());
|
||||||
}
|
}
|
||||||
ret.mySubstitutionMap.put(typeParameter, mapping);
|
return new PsiSubstitutorImpl(new UnmodifiableTHashMap<>(PSI_EQUIVALENCE, mySubstitutionMap, typeParameter, mapping));
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void putAllInternal(@NotNull PsiClass parentClass, PsiType[] mappings) {
|
private static Map<PsiTypeParameter, PsiType> putAllInternal(Map<PsiTypeParameter, PsiType> originalMap, @NotNull PsiClass parentClass,
|
||||||
|
PsiType[] mappings) {
|
||||||
final PsiTypeParameter[] params = parentClass.getTypeParameters();
|
final PsiTypeParameter[] params = parentClass.getTypeParameters();
|
||||||
|
if (params.length == 0) return originalMap;
|
||||||
|
Map<PsiTypeParameter, PsiType> newMap = new THashMap<>(originalMap);
|
||||||
|
|
||||||
for (int i = 0; i < params.length; i++) {
|
for (int i = 0; i < params.length; i++) {
|
||||||
PsiTypeParameter param = params[i];
|
PsiTypeParameter param = params[i];
|
||||||
assert param != null;
|
assert param != null;
|
||||||
if (mappings != null && mappings.length > i) {
|
if (mappings != null && mappings.length > i) {
|
||||||
PsiType mapping = mappings[i];
|
PsiType mapping = mappings[i];
|
||||||
mySubstitutionMap.put(param, mapping);
|
newMap.put(param, mapping);
|
||||||
if (mapping != null && !mapping.isValid()) {
|
if (mapping != null && !mapping.isValid()) {
|
||||||
LOG.error("Invalid type in substitutor: " + mapping);
|
LOG.error("Invalid type in substitutor: " + mapping);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
mySubstitutionMap.put(param, null);
|
newMap.put(param, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return new UnmodifiableTHashMap<>(PSI_EQUIVALENCE, newMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public PsiSubstitutor putAll(@NotNull PsiClass parentClass, PsiType[] mappings) {
|
public PsiSubstitutor putAll(@NotNull PsiClass parentClass, PsiType[] mappings) {
|
||||||
PsiSubstitutorImpl substitutor = clone();
|
return new PsiSubstitutorImpl(putAllInternal(mySubstitutionMap, parentClass, mappings));
|
||||||
substitutor.putAllInternal(parentClass, mappings);
|
|
||||||
return substitutor;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -350,9 +345,9 @@ public class PsiSubstitutorImpl implements PsiSubstitutor {
|
|||||||
public PsiSubstitutor putAll(@NotNull PsiSubstitutor another) {
|
public PsiSubstitutor putAll(@NotNull PsiSubstitutor another) {
|
||||||
if (another instanceof EmptySubstitutorImpl) return this;
|
if (another instanceof EmptySubstitutorImpl) return this;
|
||||||
final PsiSubstitutorImpl anotherImpl = (PsiSubstitutorImpl)another;
|
final PsiSubstitutorImpl anotherImpl = (PsiSubstitutorImpl)another;
|
||||||
PsiSubstitutorImpl substitutor = clone();
|
Map<PsiTypeParameter, PsiType> newMap = new THashMap<>(mySubstitutionMap, PSI_EQUIVALENCE);
|
||||||
substitutor.mySubstitutionMap.putAll(anotherImpl.mySubstitutionMap);
|
newMap.putAll(anotherImpl.mySubstitutionMap);
|
||||||
return substitutor;
|
return createSubstitutor(newMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -389,7 +384,7 @@ public class PsiSubstitutorImpl implements PsiSubstitutor {
|
|||||||
@NotNull
|
@NotNull
|
||||||
public static PsiSubstitutor createSubstitutor(@Nullable Map<PsiTypeParameter, PsiType> map) {
|
public static PsiSubstitutor createSubstitutor(@Nullable Map<PsiTypeParameter, PsiType> map) {
|
||||||
if (map == null || map.isEmpty()) return EMPTY;
|
if (map == null || map.isEmpty()) return EMPTY;
|
||||||
return new PsiSubstitutorImpl(map);
|
return new PsiSubstitutorImpl(new UnmodifiableTHashMap<>(map));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -412,6 +407,6 @@ public class PsiSubstitutorImpl implements PsiSubstitutor {
|
|||||||
@Override
|
@Override
|
||||||
@NotNull
|
@NotNull
|
||||||
public Map<PsiTypeParameter, PsiType> getSubstitutionMap() {
|
public Map<PsiTypeParameter, PsiType> getSubstitutionMap() {
|
||||||
return Collections.unmodifiableMap(mySubstitutionMap);
|
return mySubstitutionMap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,86 @@
|
|||||||
|
// Copyright 2000-2018 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.containers;
|
||||||
|
|
||||||
|
import gnu.trove.THashMap;
|
||||||
|
import gnu.trove.TObjectFunction;
|
||||||
|
import gnu.trove.TObjectHashingStrategy;
|
||||||
|
import gnu.trove.TObjectObjectProcedure;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class UnmodifiableTHashMap<K,V> extends THashMap<K,V> {
|
||||||
|
public UnmodifiableTHashMap(@NotNull Map<? extends K, ? extends V> map) {
|
||||||
|
//noinspection unchecked
|
||||||
|
this(CANONICAL, map);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UnmodifiableTHashMap(@NotNull TObjectHashingStrategy<K> strategy,
|
||||||
|
@NotNull Map<? extends K, ? extends V> map) {
|
||||||
|
super(map.size(), strategy);
|
||||||
|
for (Map.Entry<? extends K, ? extends V> e : map.entrySet()) {
|
||||||
|
super.put(e.getKey(), e.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public UnmodifiableTHashMap(@NotNull TObjectHashingStrategy<K> strategy,
|
||||||
|
@NotNull Map<? extends K, ? extends V> map, K additionalKey, V additionalValue) {
|
||||||
|
this(strategy, map);
|
||||||
|
super.put(additionalKey, additionalValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public V put(K key, V value) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean retainEntries(TObjectObjectProcedure<K, V> procedure) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void transformValues(TObjectFunction<V, V> function) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clear() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public V remove(Object key) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void removeAt(int index) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putAll(Map<? extends K, ? extends V> map) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public Collection<V> values() {
|
||||||
|
return Collections.unmodifiableCollection(super.values());
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public Set<K> keySet() {
|
||||||
|
return Collections.unmodifiableSet(super.keySet());
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public Set<Map.Entry<K, V>> entrySet() {
|
||||||
|
return Collections.unmodifiableSet(super.entrySet());
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user