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.asm;
021
022import org.objectweb.asm.Label;
023import org.objectweb.asm.Opcodes;
024import org.objectweb.asm.Type;
025import org.objectweb.asm.commons.EmptyVisitor;
026import org.sonar.java.bytecode.asm.AsmClassProvider.DETAIL_LEVEL;
027import org.sonar.squid.api.SourceCodeEdgeUsage;
028
029public class AsmMethodVisitor extends EmptyVisitor {
030
031  private AsmMethod method;
032  private AsmClassProvider asmClassProvider;
033  private int lineNumber = 0;
034  private boolean emptyMethod = true;
035
036  public AsmMethodVisitor(AsmMethod method, AsmClassProvider asmClassProvider) {
037    this.method = method;
038    this.asmClassProvider = asmClassProvider;
039    emptyMethod = true;
040  }
041
042  @Override
043  public void visitFieldInsn(int opcode, String owner, String fieldName, String fieldDescription) {
044    AsmClass targetClass = asmClassProvider.getClass(owner, DETAIL_LEVEL.NOTHING);
045    AsmField targetField = targetClass.getFieldOrCreateIt(fieldName);
046    method.addEdge(new AsmEdge(method, targetField, SourceCodeEdgeUsage.CALLS_FIELD, lineNumber));
047    emptyMethod = false;
048  }
049
050  @Override
051  public void visitMethodInsn(int opcode, String owner, String methodName, String methodDescription) {
052    if (isNotCallToJavaArrayMethod(owner)) {
053      AsmClass targetClass = asmClassProvider.getClass(owner, DETAIL_LEVEL.STRUCTURE);
054      AsmMethod targetMethod = targetClass.getMethodOrCreateIt(methodName + methodDescription);
055      method.addEdge(new AsmEdge(method, targetMethod, SourceCodeEdgeUsage.CALLS_METHOD, lineNumber));
056    }
057    emptyMethod = false;
058  }
059
060  private boolean isNotCallToJavaArrayMethod(String internalName) {
061    return internalName.charAt(0) != '[';
062  }
063
064  @Override
065  public void visitTryCatchBlock(Label start, Label end, Label handler, String exception) {
066    if (exception != null) {
067      AsmClass exceptionClass = asmClassProvider.getClass(exception, DETAIL_LEVEL.NOTHING);
068      method.addEdge(new AsmEdge(method, exceptionClass, SourceCodeEdgeUsage.USES, lineNumber));
069    }
070    emptyMethod = false;
071  }
072
073  @Override
074  public void visitTypeInsn(int opcode, String internalName) {
075    AsmClass usedClass = asmClassProvider.getClass(internalName, DETAIL_LEVEL.NOTHING);
076    method.addEdge(new AsmEdge(method, usedClass, SourceCodeEdgeUsage.USES, lineNumber));
077    emptyMethod = false;
078  }
079
080  @Override
081  public void visitLineNumber(final int line, final Label start) {
082    lineNumber = line;
083  }
084
085  @Override
086  public void visitEnd() {
087    method.setEmpty(emptyMethod);
088  }
089
090  @Override
091  public void visitIincInsn(int var, int increment) {
092    emptyMethod = false;
093  }
094
095  @Override
096  public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) {
097    emptyMethod = false;
098  }
099
100  @Override
101  public void visitInsn(int opcode) {
102    if (opcode != Opcodes.RETURN) {
103      emptyMethod = false;
104    }
105  }
106
107  @Override
108  public void visitIntInsn(int opcode, int operand) {
109    emptyMethod = false;
110  }
111
112  @Override
113  public void visitJumpInsn(int opcode, Label label) {
114    emptyMethod = false;
115  }
116
117  @Override
118  public void visitLdcInsn(Object cst) {
119    if (cst instanceof Type) {
120      Type type = (Type) cst;
121      AsmClass usedClass = asmClassProvider.getClass(type.getInternalName(), DETAIL_LEVEL.NOTHING);
122      method.addEdge(new AsmEdge(method, usedClass, SourceCodeEdgeUsage.USES, lineNumber));
123    }
124    emptyMethod = false;
125  }
126
127  @Override
128  public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
129    emptyMethod = false;
130  }
131
132  @Override
133  public void visitMultiANewArrayInsn(String desc, int dims) {
134    emptyMethod = false;
135  }
136
137  @Override
138  public void visitTableSwitchInsn(int min, int max, Label dflt, Label[] labels) {
139    emptyMethod = false;
140  }
141
142  @Override
143  public void visitVarInsn(int opcode, int var) {
144    emptyMethod = false;
145  }
146}