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;
021
022 import org.sonar.java.bytecode.asm.*;
023 import org.sonar.java.bytecode.asm.AsmClassProvider.DETAIL_LEVEL;
024 import org.sonar.java.bytecode.loader.SquidClassLoader;
025 import org.sonar.java.bytecode.visitor.*;
026 import org.sonar.squid.api.CodeScanner;
027 import org.sonar.squid.api.CodeVisitor;
028 import org.sonar.squid.api.SourceClass;
029 import org.sonar.squid.api.SourceCode;
030 import org.sonar.squid.indexer.QueryByType;
031 import org.sonar.squid.indexer.SquidIndex;
032
033 import java.io.File;
034 import java.util.ArrayList;
035 import java.util.Arrays;
036 import java.util.Collection;
037 import java.util.List;
038
039 public class BytecodeScanner extends CodeScanner<BytecodeVisitor> {
040
041 private SquidIndex indexer;
042
043 public BytecodeScanner(SquidIndex indexer) {
044 this.indexer = indexer;
045 }
046
047 public BytecodeScanner scan(Collection<File> bytecodeFilesOrDirectories) {
048 Collection<SourceCode> classes = indexer.search(new QueryByType(SourceClass.class));
049 ClassLoader classLoader = ClassLoaderBuilder.create(bytecodeFilesOrDirectories);
050 scan(classes, new AsmClassProviderImpl(classLoader));
051 ((SquidClassLoader) classLoader).close(); // TODO unchecked cast
052 return this;
053 }
054
055 public BytecodeScanner scanDirectory(File bytecodeDirectory) {
056 return scan(Arrays.asList(bytecodeDirectory));
057 }
058
059 protected BytecodeScanner scan(Collection<SourceCode> classes, AsmClassProvider classProvider) {
060 loadByteCodeInformation(classes, classProvider);
061 linkVirtualMethods(classes, classProvider);
062 notifyBytecodeVisitors(classes, classProvider);
063 return this;
064 }
065
066 private void linkVirtualMethods(Collection<SourceCode> classes, AsmClassProvider classProvider) {
067 VirtualMethodsLinker linker = new VirtualMethodsLinker();
068 for (SourceCode sourceCode : classes) {
069 AsmClass asmClass = classProvider.getClass(sourceCode.getKey(), DETAIL_LEVEL.STRUCTURE_AND_CALLS);
070 for (AsmMethod method : asmClass.getMethods()) {
071 linker.process(method);
072 }
073 }
074 }
075
076 private void notifyBytecodeVisitors(Collection<SourceCode> classes, AsmClassProvider classProvider) {
077 BytecodeVisitor[] visitorArray = getVisitors().toArray(new BytecodeVisitor[getVisitors().size()]);
078 for (SourceCode sourceCode : classes) {
079 AsmClass asmClass = classProvider.getClass(sourceCode.getKey(), DETAIL_LEVEL.STRUCTURE_AND_CALLS);
080 BytecodeVisitorNotifier visitorNotifier = new BytecodeVisitorNotifier(asmClass, visitorArray);
081 visitorNotifier.notifyVisitors(indexer);
082 }
083 }
084
085 private void loadByteCodeInformation(Collection<SourceCode> classes, AsmClassProvider classProvider) {
086 for (SourceCode sourceCode : classes) {
087 classProvider.getClass(sourceCode.getKey(), DETAIL_LEVEL.STRUCTURE_AND_CALLS);
088 }
089 }
090
091 @Override
092 public Collection<Class<? extends BytecodeVisitor>> getVisitorClasses() {
093 List<Class<? extends BytecodeVisitor>> visitorClasses = new ArrayList<Class<? extends BytecodeVisitor>>();
094 visitorClasses.add(DITVisitor.class);
095 visitorClasses.add(RFCVisitor.class);
096 visitorClasses.add(NOCVisitor.class);
097 visitorClasses.add(LCOM4Visitor.class);
098 visitorClasses.add(DependenciesVisitor.class);
099 return visitorClasses;
100 }
101
102 @Override
103 public void accept(CodeVisitor visitor) {
104 if (visitor instanceof BytecodeVisitor) {
105 super.accept(visitor);
106 }
107 }
108 }