blob: dd1044582297c003fc7f8c5ea213adf1701b49ed [file] [log] [blame]
/*
* Copyright 2000-2009 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.psi;
import com.intellij.openapi.diagnostic.Logger;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author peter
*/
public final class PsiElementRef<T extends PsiElement> {
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.PsiElementRef");
private volatile PsiRefColleague<T> myColleague;
public PsiElementRef(PsiRefColleague<T> colleague) {
myColleague = colleague;
}
public final boolean isImaginary() {
return getPsiElement() == null;
}
@Nullable
public final T getPsiElement() {
return myColleague.getPsiElement();
}
@NotNull
public final T ensurePsiElementExists() {
final PsiRefColleague.Real<T> realColleague = myColleague.makeReal();
myColleague = realColleague;
return realColleague.getPsiElement();
}
@NotNull
public final PsiElement getRoot() {
return myColleague.getRoot();
}
@Override
public boolean equals(Object o) {
return o instanceof PsiElementRef && myColleague.equals(((PsiElementRef) o).myColleague);
}
@Override
public int hashCode() {
return myColleague.hashCode();
}
public final boolean isValid() {
return myColleague.isValid();
}
public static <T extends PsiElement> PsiElementRef<T> real(@NotNull final T element) {
return new PsiElementRef<T>(new PsiRefColleague.Real<T>(element));
}
public static <Child extends PsiElement, Parent extends PsiElement> PsiElementRef<Child> imaginary(final PsiElementRef<? extends Parent> parent, final PsiRefElementCreator<Parent, Child> creator) {
return new PsiElementRef<Child>(new PsiRefColleague.Imaginary<Child, Parent>(parent, creator));
}
public PsiManager getPsiManager() {
return myColleague.getRoot().getManager();
}
private interface PsiRefColleague<T extends PsiElement> {
boolean isValid();
@Nullable
T getPsiElement();
@NotNull
Real<T> makeReal();
@NotNull
PsiElement getRoot();
class Real<T extends PsiElement> implements PsiRefColleague<T> {
private final T myElement;
public Real(@NotNull T element) {
LOG.assertTrue(element.isValid());
myElement = element;
}
@Override
@NotNull
public T getPsiElement() {
return myElement;
}
@Override
public boolean isValid() {
return myElement.isValid();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Real real = (Real)o;
if (!myElement.equals(real.myElement)) return false;
return true;
}
@Override
public int hashCode() {
return myElement.hashCode();
}
@Override
@NotNull
public Real<T> makeReal() {
return this;
}
@Override
@NotNull
public PsiElement getRoot() {
return myElement;
}
}
class Imaginary<Child extends PsiElement, Parent extends PsiElement> implements PsiRefColleague<Child> {
private final PsiElementRef<? extends Parent> myParent;
private final PsiRefElementCreator<Parent, Child> myCreator;
public Imaginary(PsiElementRef<? extends Parent> parent, PsiRefElementCreator<Parent, Child> creator) {
myParent = parent;
myCreator = creator;
}
@Override
public boolean isValid() {
return myParent.isValid();
}
@Override
public Child getPsiElement() {
return null;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Imaginary imaginary = (Imaginary)o;
if (!myCreator.equals(imaginary.myCreator)) return false;
if (!myParent.equals(imaginary.myParent)) return false;
return true;
}
@Override
public int hashCode() {
int result = myParent.hashCode();
result = 31 * result + myCreator.hashCode();
return result;
}
@Override
@NotNull
public Real<Child> makeReal() {
return new Real<Child>(myCreator.createChild(myParent.ensurePsiElementExists()));
}
@Override
@NotNull
public PsiElement getRoot() {
return myParent.getRoot();
}
}
}
}