update copyright
[fedora-idea.git] / java / java-impl / src / com / intellij / util / xml / impl / ExtendsClassChecker.java
blob5bdba4cb4c3c435a764248199adb82401b999eda
1 /*
2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com.intellij.util.xml.impl;
18 import com.intellij.openapi.project.Project;
19 import com.intellij.psi.*;
20 import com.intellij.psi.impl.source.resolve.reference.impl.providers.JavaClassReference;
21 import com.intellij.psi.impl.source.resolve.reference.impl.providers.JavaClassReferenceProvider;
22 import com.intellij.psi.search.GlobalSearchScope;
23 import com.intellij.psi.util.InheritanceUtil;
24 import com.intellij.util.ReflectionCache;
25 import com.intellij.util.SmartList;
26 import com.intellij.util.ProcessingContext;
27 import com.intellij.util.xml.*;
28 import com.intellij.util.xml.highlighting.DomCustomAnnotationChecker;
29 import com.intellij.util.xml.highlighting.DomElementAnnotationHolder;
30 import com.intellij.util.xml.highlighting.DomElementProblemDescriptor;
31 import com.intellij.util.xml.highlighting.DomHighlightingHelper;
32 import org.jetbrains.annotations.NotNull;
34 import java.util.Collections;
35 import java.util.List;
37 /**
38 * @author peter
40 public class ExtendsClassChecker extends DomCustomAnnotationChecker<ExtendClass>{
41 private static final GenericValueReferenceProvider ourProvider = new GenericValueReferenceProvider();
43 @NotNull
44 public Class<ExtendClass> getAnnotationClass() {
45 return ExtendClass.class;
48 public List<DomElementProblemDescriptor> checkForProblems(@NotNull final ExtendClass extend, @NotNull final DomElement _element, @NotNull final DomElementAnnotationHolder holder,
49 @NotNull final DomHighlightingHelper helper) {
50 if (!(_element instanceof GenericDomValue)) return Collections.emptyList();
51 GenericDomValue element = (GenericDomValue)_element;
53 final Class genericValueParameter = DomUtil.getGenericValueParameter(element.getDomElementType());
54 if (genericValueParameter == null || (!ReflectionCache.isAssignable(genericValueParameter, PsiClass.class) &&
55 !ReflectionCache.isAssignable(genericValueParameter, PsiType.class))) {
56 return Collections.emptyList();
59 final Object valueObject = element.getValue();
60 PsiClass psiClass = null;
62 if (valueObject instanceof PsiClass) {
63 psiClass = (PsiClass)valueObject;
64 } else if (valueObject instanceof PsiClassType) {
65 psiClass = ((PsiClassType)valueObject).resolve();
68 if (psiClass != null) {
69 return checkExtendClass(element, psiClass, extend.value(),
70 extend.instantiatable(), extend.canBeDecorator(), extend.allowInterface(),
71 extend.allowNonPublic(), extend.allowAbstract(), extend.allowEnum(), holder);
73 return Collections.emptyList();
76 @NotNull
77 public static List<DomElementProblemDescriptor> checkExtendClass(final GenericDomValue element, final PsiClass value, final String name,
78 final boolean instantiatable, final boolean canBeDecorator, final boolean allowInterface,
79 final boolean allowNonPublic,
80 final boolean allowAbstract,
81 final boolean allowEnum,
82 final DomElementAnnotationHolder holder) {
83 final Project project = element.getManager().getProject();
84 PsiClass extendClass = JavaPsiFacade.getInstance(project).findClass(name, GlobalSearchScope.allScope(project));
85 final SmartList<DomElementProblemDescriptor> list = new SmartList<DomElementProblemDescriptor>();
86 if (extendClass != null) {
87 if (!name.equals(value.getQualifiedName()) && !value.isInheritor(extendClass, true)) {
88 String message = DomBundle.message("class.is.not.a.subclass", value.getQualifiedName(), extendClass.getQualifiedName());
89 list.add(holder.createProblem(element, message));
93 if (instantiatable) {
94 if (value.hasModifierProperty(PsiModifier.ABSTRACT)) {
95 list.add(holder.createProblem(element, DomBundle.message("class.is.not.concrete", value.getQualifiedName())));
97 else if (!allowNonPublic && !value.hasModifierProperty(PsiModifier.PUBLIC)) {
98 list.add(holder.createProblem(element, DomBundle.message("class.is.not.public", value.getQualifiedName())));
100 else if (!hasDefaultConstructor(value)) {
101 if (canBeDecorator) {
102 boolean hasConstructor = false;
104 for (PsiMethod method : value.getConstructors()) {
105 final PsiParameterList psiParameterList = method.getParameterList();
106 if (psiParameterList.getParametersCount() != 1) continue;
107 final PsiType psiType = psiParameterList.getParameters()[0].getTypeElement().getType();
108 if (psiType instanceof PsiClassType) {
109 final PsiClass psiClass = ((PsiClassType)psiType).resolve();
110 if (psiClass != null && InheritanceUtil.isInheritorOrSelf(psiClass, extendClass, true)) {
111 hasConstructor = true;
112 break;
116 if (!hasConstructor) {
117 list.add(holder.createProblem(element, DomBundle.message("class.decorator.or.has.default.constructor", value.getQualifiedName())));
120 else {
121 list.add(holder.createProblem(element, DomBundle.message("class.has.no.default.constructor", value.getQualifiedName())));
125 if (!allowInterface && value.isInterface()) {
126 list.add(holder.createProblem(element, DomBundle.message("interface.not.allowed", value.getQualifiedName())));
128 if (!allowEnum && value.isEnum()) {
129 list.add(holder.createProblem(element, DomBundle.message("enum.not.allowed", value.getQualifiedName())));
131 if (!allowAbstract && value.hasModifierProperty(PsiModifier.ABSTRACT) && !value.isInterface()) {
132 list.add(holder.createProblem(element, DomBundle.message("abstract.class.not.allowed", value.getQualifiedName())));
134 return list;
137 public static boolean hasDefaultConstructor(PsiClass clazz) {
138 final PsiMethod[] constructors = clazz.getConstructors();
139 if (constructors.length > 0) {
140 for (PsiMethod cls: constructors) {
141 if ((cls.hasModifierProperty(PsiModifier.PUBLIC) || cls.hasModifierProperty(PsiModifier.PROTECTED)) && cls.getParameterList().getParametersCount() == 0) {
142 return true;
145 } else {
146 final PsiClass superClass = clazz.getSuperClass();
147 return superClass == null || hasDefaultConstructor(superClass);
149 return false;
152 public static List<DomElementProblemDescriptor> checkExtendsClassInReferences(final GenericDomValue element, final DomElementAnnotationHolder holder) {
153 final Object valueObject = element.getValue();
154 if (!(valueObject instanceof PsiClass)) return Collections.emptyList();
156 final PsiReference[] references = ourProvider.getReferencesByElement(DomUtil.getValueElement(element), new ProcessingContext());
157 for (PsiReference reference : references) {
158 if (reference instanceof JavaClassReference) {
159 final PsiReferenceProvider psiReferenceProvider = ((JavaClassReference)reference).getProvider();
160 final String[] value = psiReferenceProvider instanceof JavaClassReferenceProvider ? JavaClassReferenceProvider.EXTEND_CLASS_NAMES
161 .getValue(((JavaClassReferenceProvider)psiReferenceProvider).getOptions()) : null;
162 if (value != null && value.length != 0) {
163 for (String className : value) {
164 final List<DomElementProblemDescriptor> problemDescriptors =
165 checkExtendClass(element, ((PsiClass)valueObject), className, false, false, true, false, true, true, holder);
166 if (!problemDescriptors.isEmpty()) {
167 return problemDescriptors;
173 return Collections.emptyList();