blob: e1057c734fcd9c4825754aa760bf1bb3e6ebce0b [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.
*/
/*
* User: anna
* Date: 20-Dec-2007
*/
package com.intellij.codeInspection.reference;
import com.intellij.codeInspection.InspectionsBundle;
import com.intellij.openapi.util.Iconable;
import com.intellij.psi.*;
import com.intellij.util.IconUtil;
import com.intellij.util.containers.Stack;
import gnu.trove.THashSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
public abstract class RefJavaElementImpl extends RefElementImpl implements RefJavaElement {
private Set<RefClass> myOutTypeReferences;
private static final int ACCESS_MODIFIER_MASK = 0x03;
private static final int ACCESS_PRIVATE = 0x00;
private static final int ACCESS_PROTECTED = 0x01;
private static final int ACCESS_PACKAGE = 0x02;
private static final int ACCESS_PUBLIC = 0x03;
private static final int IS_STATIC_MASK = 0x04;
private static final int IS_FINAL_MASK = 0x08;
private static final int IS_USES_DEPRECATION_MASK = 0x200;
private static final int IS_SYNTHETIC_JSP_ELEMENT = 0x400;
protected RefJavaElementImpl(String name, @NotNull RefJavaElement owner) {
super(name, owner);
String am = owner.getAccessModifier();
doSetAccessModifier(am);
final boolean synthOwner = owner.isSyntheticJSP();
if (synthOwner) {
setSyntheticJSP(true);
}
}
protected RefJavaElementImpl(PsiFile file, RefManager manager) {
super(file, manager);
}
protected RefJavaElementImpl(PsiModifierListOwner elem, RefManager manager) {
super(getName(elem), elem, manager);
setAccessModifier(RefJavaUtil.getInstance().getAccessModifier(elem));
final boolean isSynth = elem instanceof PsiMethod && elem instanceof SyntheticElement || elem instanceof PsiSyntheticClass;
if (isSynth) {
setSyntheticJSP(true);
}
setIsStatic(elem.hasModifierProperty(PsiModifier.STATIC));
setIsFinal(elem.hasModifierProperty(PsiModifier.FINAL));
}
@Override
@NotNull
public Collection<RefClass> getOutTypeReferences() {
if (myOutTypeReferences == null){
return Collections.emptySet();
}
return myOutTypeReferences;
}
public void addOutTypeRefernce(RefClass refClass){
if (myOutTypeReferences == null){
myOutTypeReferences = new THashSet<RefClass>();
}
myOutTypeReferences.add(refClass);
}
public static String getName(PsiElement element) {
if (element instanceof PsiAnonymousClass) {
PsiAnonymousClass psiAnonymousClass = (PsiAnonymousClass)element;
PsiClass psiBaseClass = psiAnonymousClass.getBaseClassType().resolve();
return InspectionsBundle.message("inspection.reference.anonymous.name", psiBaseClass == null ? "" : psiBaseClass.getQualifiedName());
}
if (element instanceof PsiSyntheticClass) {
final PsiSyntheticClass jspClass = (PsiSyntheticClass)element;
final PsiFile jspxFile = jspClass.getContainingFile();
return "<" + jspxFile.getName() + ">";
}
if (element instanceof PsiMethod && element instanceof SyntheticElement ) {
return InspectionsBundle.message("inspection.reference.jsp.holder.method.anonymous.name");
}
String name = null;
if (element instanceof PsiNamedElement) {
name = ((PsiNamedElement)element).getName();
}
return name == null ? InspectionsBundle.message("inspection.reference.anonymous") : name;
}
@Override
public boolean isFinal() {
return checkFlag(IS_FINAL_MASK);
}
@Override
public boolean isStatic() {
return checkFlag(IS_STATIC_MASK);
}
public void setIsStatic(boolean isStatic) {
setFlag(isStatic, IS_STATIC_MASK);
}
@Override
public boolean isUsesDeprecatedApi() {
return checkFlag(IS_USES_DEPRECATION_MASK);
}
public void setUsesDeprecatedApi(boolean usesDeprecatedApi) {
setFlag(usesDeprecatedApi, IS_USES_DEPRECATION_MASK);
}
public void setIsFinal(boolean isFinal) {
setFlag(isFinal, IS_FINAL_MASK);
}
public void setReachable(boolean reachable) {
setFlag(reachable, IS_REACHABLE_MASK);
}
@Override
public boolean isSyntheticJSP() {
return checkFlag(IS_SYNTHETIC_JSP_ELEMENT);
}
public void setSyntheticJSP(boolean b) {
setFlag(b, IS_SYNTHETIC_JSP_ELEMENT);
}
@Override
@Nullable
public String getAccessModifier() {
long access_id = myFlags & ACCESS_MODIFIER_MASK;
if (access_id == ACCESS_PRIVATE) return PsiModifier.PRIVATE;
if (access_id == ACCESS_PUBLIC) return PsiModifier.PUBLIC;
if (access_id == ACCESS_PACKAGE) return PsiModifier.PACKAGE_LOCAL;
return PsiModifier.PROTECTED;
}
public void setAccessModifier(String am) {
doSetAccessModifier(am);
}
private void doSetAccessModifier(String am) {
final int access_id;
if (PsiModifier.PRIVATE.equals(am)) {
access_id = ACCESS_PRIVATE;
}
else if (PsiModifier.PUBLIC.equals(am)) {
access_id = ACCESS_PUBLIC;
}
else if (PsiModifier.PACKAGE_LOCAL.equals(am)) {
access_id = ACCESS_PACKAGE;
}
else {
access_id = ACCESS_PROTECTED;
}
myFlags = myFlags & ~0x3 | access_id;
}
public boolean isSuspiciousRecursive() {
return isCalledOnlyFrom(this, new Stack<RefJavaElement>());
}
private boolean isCalledOnlyFrom(RefJavaElement refElement, Stack<RefJavaElement> callStack) {
if (callStack.contains(this)) return refElement == this;
if (getInReferences().isEmpty()) return false;
if (refElement instanceof RefMethod) {
RefMethod refMethod = (RefMethod) refElement;
for (RefMethod refSuper : refMethod.getSuperMethods()) {
if (!refSuper.getInReferences().isEmpty()) return false;
}
if (refMethod.isConstructor()){
boolean unreachable = true;
for (RefElement refOut : refMethod.getOutReferences()){
unreachable &= !refOut.isReachable();
}
if (unreachable) return true;
}
}
callStack.push(this);
for (RefElement refCaller : getInReferences()) {
if (!((RefElementImpl)refCaller).isSuspicious() || !((RefJavaElementImpl)refCaller).isCalledOnlyFrom(refElement, callStack)) {
callStack.pop();
return false;
}
}
callStack.pop();
return true;
}
public void addReference(RefElement refWhat, PsiElement psiWhat, PsiElement psiFrom, boolean forWriting, boolean forReading, PsiReferenceExpression expression) {
if (refWhat != null) {
if (refWhat instanceof RefParameter) {
if (forWriting) {
((RefParameter)refWhat).parameterReferenced(true);
}
if (forReading) {
((RefParameter)refWhat).parameterReferenced(false);
}
}
addOutReference(refWhat);
((RefJavaElementImpl)refWhat).markReferenced(this, psiFrom, psiWhat, forWriting, forReading, expression);
} else {
if (psiWhat instanceof PsiMethod) {
final PsiClass containingClass = ((PsiMethod)psiWhat).getContainingClass();
if (containingClass != null && containingClass.isEnum() && "values".equals(((PsiMethod)psiWhat).getName())) {
for (PsiField enumConstant : containingClass.getFields()) {
if (enumConstant instanceof PsiEnumConstant) {
final RefJavaElementImpl enumConstantReference = (RefJavaElementImpl)getRefManager().getReference(enumConstant);
if (enumConstantReference != null) {
addOutReference(enumConstantReference);
enumConstantReference.markReferenced(this, psiFrom, enumConstant, false, true, expression);
}
}
}
}
}
getRefManager().fireNodeMarkedReferenced(psiWhat, psiFrom, false);
}
}
protected void markReferenced(final RefElementImpl refFrom, PsiElement psiFrom, PsiElement psiWhat, final boolean forWriting, boolean forReading, PsiReferenceExpression expressionFrom) {
addInReference(refFrom);
getRefManager().fireNodeMarkedReferenced(this, refFrom, false, forReading, forWriting);
}
protected RefJavaManager getRefJavaManager() {
return getRefManager().getExtension(RefJavaManager.MANAGER);
}
@Override
public void referenceRemoved() {
super.referenceRemoved();
if (isEntry()) {
getRefJavaManager().getEntryPointsManager().removeEntryPoint(this);
}
}
@Override
public Icon getIcon(final boolean expanded) {
if (isSyntheticJSP()) {
final PsiElement element = getElement();
if (element != null && element.isValid()) {
return IconUtil.getIcon(element.getContainingFile().getVirtualFile(),
Iconable.ICON_FLAG_VISIBILITY | Iconable.ICON_FLAG_READ_STATUS, element.getProject());
}
}
return super.getIcon(expanded);
}
}