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 */
020package org.sonar.java.bytecode;
021
022import org.sonar.java.bytecode.asm.*;
023import org.sonar.java.bytecode.asm.AsmClassProvider.DETAIL_LEVEL;
024import org.sonar.java.bytecode.loader.SquidClassLoader;
025import org.sonar.java.bytecode.visitor.*;
026import org.sonar.squid.api.CodeScanner;
027import org.sonar.squid.api.CodeVisitor;
028import org.sonar.squid.api.SourceClass;
029import org.sonar.squid.api.SourceCode;
030import org.sonar.squid.indexer.QueryByType;
031import org.sonar.squid.indexer.SquidIndex;
032
033import java.io.File;
034import java.util.ArrayList;
035import java.util.Arrays;
036import java.util.Collection;
037import java.util.List;
038
039public 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}