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    }