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