001 /* 002 * Sonar, open source software quality management tool. 003 * Copyright (C) 2009 SonarSource SA 004 * mailto:contact AT sonarsource DOT com 005 * 006 * Sonar is free software; you can redistribute it and/or 007 * modify it under the terms of the GNU Lesser General Public 008 * License as published by the Free Software Foundation; either 009 * version 3 of the License, or (at your option) any later version. 010 * 011 * Sonar is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 * Lesser General Public License for more details. 015 * 016 * You should have received a copy of the GNU Lesser General Public 017 * License along with Sonar; if not, write to the Free Software 018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 019 */ 020 package org.sonar.squid.bytecode; 021 022 import java.util.Set; 023 024 import org.sonar.squid.api.SourceClass; 025 import org.sonar.squid.api.SourceFile; 026 import org.sonar.squid.api.SourcePackage; 027 import org.sonar.squid.api.SourceCode; 028 import org.sonar.squid.graph.Edge; 029 import org.sonar.squid.graph.EdgeUsage; 030 import org.sonar.squid.measures.Metric; 031 032 public class DependencyVisitor extends AsmVisitor { 033 034 @Override 035 protected void visitClass(AccessFlags accessFlags, SourceClass currentClass, SourceClass superClass, Set<SourceClass> interfaces, 036 Set<SourceClass> generics) { 037 link(currentClass, superClass, EdgeUsage.EXTENDS); 038 link(currentClass, interfaces, EdgeUsage.IMPLEMENTS); 039 link(currentClass, generics, EdgeUsage.CONTAINS); 040 } 041 042 @Override 043 public void visitField(AccessFlags accessFlags, SourceClass currentClass, String fieldName, SourceClass fieldResource, 044 Set<SourceClass> generics, SourceClass value) { 045 link(currentClass, fieldResource, EdgeUsage.CONTAINS); 046 link(currentClass, generics, EdgeUsage.CONTAINS); 047 link(currentClass, value, EdgeUsage.USES); 048 } 049 050 @Override 051 public void visitMethod(AccessFlags accessFlags, SourceClass currentClass, String methodName, SourceClass returnResource, 052 Set<SourceClass> argResources, Set<SourceClass> generics, Set<SourceClass> exceptions) { 053 link(currentClass, returnResource, EdgeUsage.USES); 054 link(currentClass, argResources, EdgeUsage.USES); 055 link(currentClass, generics, EdgeUsage.USES); 056 link(currentClass, exceptions, EdgeUsage.USES); 057 } 058 059 @Override 060 public void visitOutsideFieldAccess(SourceClass currentClass, SourceClass fieldOwner, SourceClass fieldType) { 061 link(currentClass, fieldOwner, EdgeUsage.USES); 062 link(currentClass, fieldType, EdgeUsage.USES); 063 } 064 065 @Override 066 public void visitTypeInsn(SourceClass currentClass, SourceClass usedClass) { 067 link(currentClass, usedClass, EdgeUsage.USES); 068 } 069 070 @Override 071 public void visitOutsideMethodAccess(SourceClass currentClass, SourceClass outsideClass, Set<SourceClass> methodArgs) { 072 link(currentClass, outsideClass, EdgeUsage.USES); 073 link(currentClass, methodArgs, EdgeUsage.USES); 074 } 075 076 @Override 077 public void visitTryCatchBlock(SourceClass currentClass, SourceClass exceptionClass) { 078 link(currentClass, exceptionClass, EdgeUsage.USES); 079 } 080 081 private void link(SourceClass from, Set<SourceClass> tos, EdgeUsage link) { 082 for (SourceClass to : tos) { 083 link(from, to, link); 084 } 085 } 086 087 private void link(SourceClass from, SourceClass to, EdgeUsage link) { 088 if (canWeLinkNodes(from, to) && from.getEdgeTo(to) == null) { 089 from.createEdgeWith(to, link); 090 from.add(Metric.CE, 1); 091 to.add(Metric.CA, 1); 092 createEdgeBetweenParents(SourceFile.class, from, to, from.getEdgeTo(to)); 093 createEdgeBetweenParents(SourcePackage.class, from, to, from.getEdgeTo(to)); 094 } 095 } 096 097 private void createEdgeBetweenParents(Class<? extends SourceCode> type, SourceClass from, SourceClass to, Edge rootEdge) { 098 SourceCode fromParent = from.getParent(type); 099 SourceCode toParent = to.getParent(type); 100 101 if (canWeLinkNodes(fromParent, toParent)) { 102 if (fromParent.getEdgeTo(toParent) == null) { 103 fromParent.createEdgeWith(toParent, EdgeUsage.USES, rootEdge); 104 fromParent.add(Metric.CE, 1); 105 toParent.add(Metric.CA, 1); 106 } else { 107 if (!fromParent.getEdgeTo(toParent).hasAnEdgeFromRootNode(from)) { 108 toParent.add(Metric.CA, 1); 109 } 110 if (!fromParent.getEdgeTo(toParent).hasAnEdgeToRootNode(to)) { 111 fromParent.add(Metric.CE, 1); 112 } 113 fromParent.getEdgeTo(toParent).addRootEdge(rootEdge); 114 } 115 } 116 } 117 118 private boolean canWeLinkNodes(SourceCode from, SourceCode to) { 119 boolean result = from != null && to != null && !from.equals(to); 120 return result; 121 } 122 123 }