| /* |
| * Copyright 2003-2005 Dave Griffith |
| * |
| * 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.siyeh.ig.classmetrics; |
| |
| import com.intellij.openapi.project.Project; |
| import com.intellij.openapi.util.text.StringUtil; |
| import com.intellij.psi.*; |
| import com.intellij.psi.search.GlobalSearchScope; |
| import com.siyeh.ig.psiutils.ClassUtils; |
| import com.siyeh.ig.psiutils.LibraryUtil; |
| import org.jetbrains.annotations.NonNls; |
| import org.jetbrains.annotations.NotNull; |
| |
| import java.util.HashSet; |
| import java.util.Set; |
| |
| class CouplingVisitor extends JavaRecursiveElementVisitor { |
| private boolean m_inClass = false; |
| private final PsiClass m_class; |
| private final boolean m_includeJavaClasses; |
| private final boolean m_includeLibraryClasses; |
| private final Set<String> m_dependencies = new HashSet<String>(10); |
| |
| CouplingVisitor(PsiClass aClass, boolean includeJavaClasses, |
| boolean includeLibraryClasses) { |
| super(); |
| m_class = aClass; |
| m_includeJavaClasses = includeJavaClasses; |
| m_includeLibraryClasses = includeLibraryClasses; |
| } |
| |
| @Override |
| public void visitField(@NotNull PsiField field) { |
| super.visitField(field); |
| final PsiType type = field.getType(); |
| addDependency(type); |
| } |
| |
| @Override |
| public void visitLocalVariable(@NotNull PsiLocalVariable var) { |
| super.visitLocalVariable(var); |
| final PsiType type = var.getType(); |
| addDependency(type); |
| } |
| |
| @Override |
| public void visitMethod(@NotNull PsiMethod method) { |
| super.visitMethod(method); |
| final PsiType returnType = method.getReturnType(); |
| addDependency(returnType); |
| addDependenciesForParameters(method); |
| addDependenciesForThrowsList(method); |
| } |
| |
| private void addDependenciesForThrowsList(PsiMethod method) { |
| final PsiReferenceList throwsList = method.getThrowsList(); |
| final PsiClassType[] throwsTypes = throwsList.getReferencedTypes(); |
| for (PsiClassType throwsType : throwsTypes) { |
| addDependency(throwsType); |
| } |
| } |
| |
| private void addDependenciesForParameters(PsiMethod method) { |
| final PsiParameterList parameterList = method.getParameterList(); |
| final PsiParameter[] parameters = parameterList.getParameters(); |
| for (PsiParameter parameter : parameters) { |
| final PsiType parameterType = parameter.getType(); |
| addDependency(parameterType); |
| } |
| } |
| |
| @Override |
| public void visitNewExpression(@NotNull PsiNewExpression exp) { |
| super.visitNewExpression(exp); |
| final PsiType classType = exp.getType(); |
| addDependency(classType); |
| } |
| |
| @Override |
| public void visitClassObjectAccessExpression(PsiClassObjectAccessExpression exp) { |
| super.visitClassObjectAccessExpression(exp); |
| final PsiTypeElement operand = exp.getOperand(); |
| final PsiType classType = operand.getType(); |
| addDependency(classType); |
| } |
| |
| @Override |
| public void visitClass(@NotNull PsiClass aClass) { |
| final boolean wasInClass = m_inClass; |
| if (!m_inClass) { |
| |
| m_inClass = true; |
| super.visitClass(aClass); |
| } |
| m_inClass = wasInClass; |
| final PsiType[] superTypes = aClass.getSuperTypes(); |
| for (PsiType superType : superTypes) { |
| addDependency(superType); |
| } |
| } |
| |
| @Override |
| public void visitTryStatement(@NotNull PsiTryStatement statement) { |
| super.visitTryStatement(statement); |
| final PsiParameter[] catchBlockParameters = statement.getCatchBlockParameters(); |
| for (PsiParameter catchBlockParameter : catchBlockParameters) { |
| final PsiType catchType = catchBlockParameter.getType(); |
| addDependency(catchType); |
| } |
| } |
| |
| @Override |
| public void visitInstanceOfExpression(@NotNull PsiInstanceOfExpression exp) { |
| super.visitInstanceOfExpression(exp); |
| final PsiTypeElement checkType = exp.getCheckType(); |
| if (checkType == null) { |
| return; |
| } |
| final PsiType classType = checkType.getType(); |
| addDependency(classType); |
| } |
| |
| @Override |
| public void visitTypeCastExpression(@NotNull PsiTypeCastExpression exp) { |
| super.visitTypeCastExpression(exp); |
| final PsiTypeElement castType = exp.getCastType(); |
| if (castType == null) { |
| return; |
| } |
| final PsiType classType = castType.getType(); |
| addDependency(classType); |
| } |
| |
| private void addDependency(PsiType type) { |
| if (type == null) { |
| return; |
| } |
| final PsiType baseType = type.getDeepComponentType(); |
| |
| if (ClassUtils.isPrimitive(type)) { |
| return; |
| } |
| final String qualifiedName = m_class.getQualifiedName(); |
| if (qualifiedName == null) { |
| return; |
| } |
| if (baseType.equalsToText(qualifiedName)) { |
| return; |
| } |
| final String baseTypeName = baseType.getCanonicalText(); |
| @NonNls final String javaPrefix = "java."; |
| @NonNls final String javaxPrefix = "javax."; |
| if (!m_includeJavaClasses && |
| (baseTypeName.startsWith(javaPrefix) || |
| baseTypeName.startsWith(javaxPrefix))) { |
| return; |
| } |
| if (!m_includeLibraryClasses) { |
| final Project project = m_class.getProject(); |
| final GlobalSearchScope searchScope = GlobalSearchScope.allScope(project); |
| final PsiClass aClass = JavaPsiFacade.getInstance(project).findClass(baseTypeName, searchScope); |
| if (aClass == null) { |
| return; |
| } |
| if (LibraryUtil.classIsInLibrary(aClass)) { |
| return; |
| } |
| } |
| if (StringUtil.startsWithConcatenation(baseTypeName, qualifiedName, ".")) { |
| return; |
| } |
| m_dependencies.add(baseTypeName); |
| } |
| |
| public int getNumDependencies() { |
| return m_dependencies.size(); |
| } |
| } |