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.java.bytecode.visitor; 021 022 import java.util.ArrayList; 023 import java.util.HashSet; 024 import java.util.List; 025 import java.util.Set; 026 027 import org.sonar.java.bytecode.asm.AsmClass; 028 import org.sonar.java.bytecode.asm.AsmEdge; 029 import org.sonar.java.bytecode.asm.AsmMethod; 030 import org.sonar.java.bytecode.asm.AsmResource; 031 import org.sonar.squid.api.SourceCodeEdgeUsage; 032 import org.sonar.squid.indexer.SquidIndex; 033 import org.sonar.squid.measures.Metric; 034 035 public class LCOM4Visitor extends BytecodeVisitor { 036 037 private AsmClass asmClass; 038 private List<Set<AsmResource>> unrelatedBlocks = null; 039 040 public LCOM4Visitor(SquidIndex index) { 041 super(index); 042 } 043 044 public void visitClass(AsmClass asmClass) { 045 this.asmClass = asmClass; 046 unrelatedBlocks = new ArrayList<Set<AsmResource>>(); 047 } 048 049 public void visitMethod(AsmMethod asmMethod) { 050 if (isMethodElligibleForLCOM4Computation(asmMethod)) { 051 Set<AsmResource> block = getResourceBlockOrCreateIt(asmMethod); 052 for (AsmEdge edge : asmMethod.getOutgoingEdges()) { 053 if (isCallToInternalFieldOrMethod(edge)) { 054 AsmResource toResource = edge.getTo(); 055 mergeAsmResourceToBlock(block, toResource); 056 } 057 } 058 } 059 } 060 061 private boolean isMethodElligibleForLCOM4Computation(AsmMethod asmMethod) { 062 return !asmMethod.isAbstract() && !asmMethod.isStatic() && !asmMethod.isConstructor() && !asmMethod.isEmpty() 063 && !asmMethod.isAccessor() && asmMethod.isBodyLoaded(); 064 } 065 066 public void leaveClass(AsmClass asmClass) { 067 //filterIsolatedMethods(); 068 int lcom4 = unrelatedBlocks.size(); 069 if (lcom4 == 0) { 070 lcom4 = 1; 071 } 072 073 getSourceClass(asmClass).add(Metric.LCOM4, lcom4); 074 getSourceClass(asmClass).addData(Metric.LCOM4_BLOCKS, unrelatedBlocks); 075 076 if (isMainPublicClassInFile(asmClass)) { 077 getSourceFile(asmClass).add(Metric.LCOM4, lcom4); 078 getSourceFile(asmClass).addData(Metric.LCOM4_BLOCKS, unrelatedBlocks); 079 } 080 } 081 082 private void mergeAsmResourceToBlock(Set<AsmResource> block, AsmResource toResource) { 083 if (block.contains(toResource)) { 084 return; 085 } 086 Set<AsmResource> otherBlock = getResourceBlock(toResource); 087 if (otherBlock == null) { 088 block.add(toResource); 089 090 } else { 091 block.addAll(otherBlock); 092 unrelatedBlocks.remove(otherBlock); 093 } 094 } 095 096 private boolean isCallToInternalFieldOrMethod(AsmEdge edge) { 097 return edge.getTargetAsmClass() == asmClass 098 && (edge.getUsage() == SourceCodeEdgeUsage.CALLS_FIELD || edge.getUsage() == SourceCodeEdgeUsage.CALLS_METHOD); 099 } 100 101 private Set<AsmResource> getResourceBlockOrCreateIt(AsmResource fromResource) { 102 Set<AsmResource> block = getResourceBlock(fromResource); 103 if (block != null) { 104 return block; 105 } 106 block = new HashSet<AsmResource>(); 107 block.add(fromResource); 108 unrelatedBlocks.add(block); 109 return block; 110 } 111 112 private Set<AsmResource> getResourceBlock(AsmResource fromResource) { 113 for (Set<AsmResource> block : unrelatedBlocks) { 114 if (block.contains(fromResource)) { 115 return block; 116 } 117 } 118 return null; 119 } 120 }