/* * 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.lang.Language; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.util.PsiUtilCore; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.lang.ref.SoftReference; /** * @author mike */ public class PsiInvalidElementAccessException extends RuntimeException { private final SoftReference<PsiElement> myElementReference; // to prevent leaks, since exceptions are stored in IdeaLogger public PsiInvalidElementAccessException(PsiElement element) { this(element, (String)null); } public PsiInvalidElementAccessException(PsiElement element, @Nullable String message) { this(element, getMessageWithReason(element, message), null); } public PsiInvalidElementAccessException(PsiElement element, @Nullable Throwable cause) { this(element, getMessageWithReason(element, null), cause); } public PsiInvalidElementAccessException(PsiElement element, @Nullable String message, @Nullable Throwable cause) { super(message, cause); myElementReference = new SoftReference<PsiElement>(element); } private static String getMessageWithReason(@Nullable PsiElement element, @Nullable String message) { return (element == null ? "Unknown psi element" : "Element: " + element.getClass() + " because: " + reason(element)) + (message == null ? "" : "; " + message); } @NonNls @NotNull private static String reason(@NotNull PsiElement root){ if (root == PsiUtilCore.NULL_PSI_ELEMENT) return "NULL_PSI_ELEMENT"; PsiElement element = root instanceof PsiFile ? root : root.getParent(); if (element == null) return "parent is null"; while (element != null && !(element instanceof PsiFile) && element.getParent() != null) { element = element.getParent(); } PsiFile file = element instanceof PsiFile ? (PsiFile)element : null; if (file == null) return "containing file is null"; FileViewProvider provider = file.getViewProvider(); VirtualFile vFile = provider.getVirtualFile(); if (!vFile.isValid()) return vFile+" is invalid"; if (!provider.isPhysical()) { PsiElement context = file.getContext(); if (context != null && !context.isValid()) { return "invalid context: " + reason(context); } return "non-physical provider: " + provider; // "dummy" file? } PsiManager manager = file.getManager(); if (manager.getProject().isDisposed()) return "project is disposed"; Language language = file.getLanguage(); if (language != provider.getBaseLanguage()) return "File language:"+language+" != Provider base language:"+provider.getBaseLanguage(); FileViewProvider provider1 = manager.findViewProvider(vFile); if (provider != provider1) return "different providers: "+provider+"("+Integer.toHexString(System.identityHashCode(provider))+"); "+provider1+"("+Integer.toHexString(System.identityHashCode(provider1))+")"; return "psi is outdated"; } @Nullable public PsiElement getPsiElement() { return myElementReference.get(); } }