001 /* 002 * Sonar, open source software quality management tool. 003 * Copyright (C) 2008-2012 SonarSource 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.java.bytecode.visitor; 021 022 import org.sonar.graph.DirectedGraph; 023 import org.sonar.java.bytecode.asm.AsmClass; 024 import org.sonar.java.bytecode.asm.AsmEdge; 025 import org.sonar.squid.api.SourceClass; 026 import org.sonar.squid.api.SourceCode; 027 import org.sonar.squid.api.SourceCodeEdge; 028 import org.sonar.squid.api.SourceCodeEdgeUsage; 029 import org.sonar.squid.api.SourceFile; 030 import org.sonar.squid.api.SourcePackage; 031 import org.sonar.squid.measures.Metric; 032 033 public class DependenciesVisitor extends BytecodeVisitor { 034 035 private SourceClass fromSourceClass; 036 private final DirectedGraph<SourceCode, SourceCodeEdge> graph; 037 038 public DependenciesVisitor(DirectedGraph<SourceCode, SourceCodeEdge> graph) { 039 this.graph = graph; 040 } 041 042 public void visitClass(AsmClass asmClass) { 043 this.fromSourceClass = getSourceClass(asmClass); 044 } 045 046 public void visitEdge(AsmEdge edge) { 047 AsmClass toAsmClass = edge.getTargetAsmClass(); 048 SourceClass toSourceClass = getSourceClass(toAsmClass); 049 switch (edge.getUsage()) { 050 case EXTENDS: 051 link(fromSourceClass, toSourceClass, SourceCodeEdgeUsage.EXTENDS); 052 break; 053 case IMPLEMENTS: 054 link(fromSourceClass, toSourceClass, SourceCodeEdgeUsage.IMPLEMENTS); 055 break; 056 default: 057 link(fromSourceClass, toSourceClass, SourceCodeEdgeUsage.USES); 058 break; 059 } 060 } 061 062 private void link(SourceClass from, SourceClass to, SourceCodeEdgeUsage link) { 063 if (canWeLinkNodes(from, to) && graph.getEdge(from, to) == null) { 064 SourceCodeEdge edge = new SourceCodeEdge(from, to, link); 065 graph.addEdge(edge); 066 from.add(Metric.CE, 1); 067 to.add(Metric.CA, 1); 068 SourceCodeEdge fileEdge = createEdgeBetweenParents(SourceFile.class, from, to, edge); 069 createEdgeBetweenParents(SourcePackage.class, from, to, fileEdge); 070 } 071 } 072 073 private SourceCodeEdge createEdgeBetweenParents(Class<? extends SourceCode> type, SourceClass from, SourceClass to, 074 SourceCodeEdge rootEdge) { 075 SourceCode fromParent = from.getParent(type); 076 SourceCode toParent = to.getParent(type); 077 SourceCodeEdge parentEdge = null; 078 if (canWeLinkNodes(fromParent, toParent) && rootEdge != null) { 079 if (graph.getEdge(fromParent, toParent) == null) { 080 parentEdge = new SourceCodeEdge(fromParent, toParent, SourceCodeEdgeUsage.USES); 081 parentEdge.addRootEdge(rootEdge); 082 graph.addEdge(parentEdge); 083 fromParent.add(Metric.CE, 1); 084 toParent.add(Metric.CA, 1); 085 } else { 086 parentEdge = graph.getEdge(fromParent, toParent); 087 if ( !parentEdge.hasAnEdgeFromRootNode(rootEdge.getFrom())) { 088 toParent.add(Metric.CA, 1); 089 } 090 if ( !parentEdge.hasAnEdgeToRootNode(rootEdge.getTo())) { 091 fromParent.add(Metric.CE, 1); 092 } 093 parentEdge.addRootEdge(rootEdge); 094 } 095 } 096 return parentEdge; 097 } 098 099 private boolean canWeLinkNodes(SourceCode from, SourceCode to) { 100 return from != null && to != null && !from.equals(to); 101 } 102 103 }