Clover coverage report - PMD - 3.9 Coverage timestamp: Tue Dec 19 2006 09:38:44 EST FRAMES NO FRAMES |
file stats: | LOC: | 147 |  | Methods: | 7
| NCLOC: | 110 |  | Classes: | 2
Source file | Conditionals | Statements | Methods | TOTAL
DynamicXPathRule.java | 93.8% | 98.3% | 100% | 97.6% |

1 |  | package net.sourceforge.pmd.rules;
2 |  |
3 |  | import java.util.HashMap;
4 |  | import java.util.Iterator;
5 |  | import java.util.List;
6 |  | import java.util.Map.Entry;
7 |  |
8 |  | import net.sourceforge.pmd.AbstractRule;
9 |  | import net.sourceforge.pmd.ast.ASTVariableDeclaratorId;
10 |  | import net.sourceforge.pmd.ast.Node;
11 |  | import net.sourceforge.pmd.ast.SimpleNode;
12 |  | import net.sourceforge.pmd.jaxen.DocumentNavigator;
13 |  | import net.sourceforge.pmd.jaxen.MatchesFunction;
14 |  |
15 |  | import org.jaxen.BaseXPath;
16 |  | import org.jaxen.JaxenException;
17 |  | import org.jaxen.SimpleVariableContext;
18 |  | import org.jaxen.XPath;
19 |  | import org.objectweb.asm.ClassWriter;
20 |  | import org.objectweb.asm.MethodVisitor;
21 |  | import org.objectweb.asm.Opcodes;
22 |  |
23 |  | public class DynamicXPathRule extends AbstractRule implements Opcodes {
24 |  |
25 | 2381 | protected DynamicXPathRule() {
26 |  | }
27 |  |
28 |  | private static HashMap classes = new HashMap();
29 |  |
30 | 2381 | public static synchronized Class loadClass(ClassLoader classloader, String type) {
31 | 2381 | Class c = (Class) classes.get(type);
32 | 2381 | if (c == null) {
33 | 1317 | byte bytecode[] = buildClass(type);
34 | 1317 | c = new ByteArrayClassLoader(classloader).loadClass(bytecode);
35 |  |
36 | 1317 | classes.put(type, c);
37 |  | }
38 |  |
39 | 2381 | return c;
40 |  | }
41 |  |
42 |  | private static class ByteArrayClassLoader extends ClassLoader {
43 | 1317 | ByteArrayClassLoader(ClassLoader parent) {
44 | 1317 | super(parent);
45 |  | }
46 |  |
47 | 1317 | Class loadClass(byte[] data) {
48 | 1317 | return defineClass(null, data, 0, data.length, null);
49 |  | }
50 |  | }
51 |  |
52 | 1317 | private static byte[] buildClass(String type) {
53 | 1317 | String className = "net/sourceforge/pmd/rules/" + type + "XPathRule";
54 | 1317 | String methodSig = "(Lnet/sourceforge/pmd/ast/AST" + type + ";Ljava/lang/Object;)Ljava/lang/Object;";
55 |  |
56 | 1317 | ClassWriter cw = new ClassWriter(0);
57 | 1317 | MethodVisitor mv;
58 |  |
59 | 1317 | cw.visit(V1_4, ACC_PUBLIC + ACC_SUPER, className, null, "net/sourceforge/pmd/rules/DynamicXPathRule", null);
60 |  |
61 | 1317 | mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
62 | 1317 | mv.visitCode();
63 | 1317 | mv.visitVarInsn(ALOAD, 0);
64 | 1317 | mv.visitMethodInsn(INVOKESPECIAL, "net/sourceforge/pmd/rules/DynamicXPathRule", "<init>", "()V");
65 | 1317 | mv.visitInsn(RETURN);
66 | 1317 | mv.visitMaxs(1, 1);
67 | 1317 | mv.visitEnd();
68 |  |
69 | 1317 | mv = cw.visitMethod(ACC_PUBLIC, "visit", methodSig, null, null);
70 | 1317 | mv.visitCode();
71 | 1317 | mv.visitVarInsn(ALOAD, 0);
72 | 1317 | mv.visitVarInsn(ALOAD, 1);
73 | 1317 | mv.visitVarInsn(ALOAD, 2);
74 | 1317 | mv.visitMethodInsn(INVOKEVIRTUAL, className, "evaluate", "(Lnet/sourceforge/pmd/ast/Node;Ljava/lang/Object;)V");
75 | 1317 | mv.visitVarInsn(ALOAD, 0);
76 | 1317 | mv.visitVarInsn(ALOAD, 1);
77 | 1317 | mv.visitVarInsn(ALOAD, 2);
78 | 1317 | mv.visitMethodInsn(INVOKESPECIAL, "net/sourceforge/pmd/rules/DynamicXPathRule", "visit", methodSig);
79 | 1317 | mv.visitInsn(ARETURN);
80 | 1317 | mv.visitMaxs(3, 3);
81 | 1317 | mv.visitEnd();
82 |  |
83 | 1317 | cw.visitEnd();
84 |  |
85 | 1317 | return cw.toByteArray();
86 |  | }
87 |  |
88 |  |
89 |  | private XPath xpath;
90 |  |
91 |  | private boolean regexpFunctionRegistered;
92 |  |
93 |  | /**
94 |  | * Evaluate the AST with compilationUnit as root-node, against
95 |  | * the XPath expression found as property with name "xpath".
96 |  | * All matches are reported as violations.
97 |  | *
98 |  | * @param compilationUnit the Node that is the root of the AST to be checked
99 |  | * @param data
100 |  | */
101 | 572 | public void evaluate(Node compilationUnit, Object data) {
102 | 572 | try {
103 | 572 | initializeXPathExpression();
104 | 572 | List results = xpath.selectNodes(compilationUnit);
105 | 572 | for (Iterator i = results.iterator(); i.hasNext();) {
106 | 209 | SimpleNode n = (SimpleNode) i.next();
107 | 209 | if (n instanceof ASTVariableDeclaratorId && getBooleanProperty("pluginname")) {
108 | 11 | addViolation(data, n, n.getImage());
109 |  | } else {
110 | 198 | addViolation(data, (SimpleNode) n, getMessage());
111 |  | }
112 |  | }
113 |  | } catch (JaxenException ex) {
114 | 0 | throw new RuntimeException(ex);
115 |  | }
116 |  | }
117 |  |
118 | 572 | private void initializeXPathExpression() throws JaxenException {
119 | 572 | if (xpath != null) {
120 | 468 | return;
121 |  | }
122 |  |
123 | 104 | if (!regexpFunctionRegistered) {
124 | 104 | MatchesFunction.registerSelfInSimpleContext();
125 | 104 | regexpFunctionRegistered = true;
126 |  | }
127 |  |
128 | 104 | String prop = getStringProperty("xpath");
129 |  |
130 | 104 | String tail = prop.trim().replaceFirst("^//\\w+", "");
131 | 104 | String subquery = '.' + tail.trim();
132 |  |
133 | 104 | xpath = new BaseXPath(subquery, new DocumentNavigator());
134 | 104 | if (properties.size() > 1) {
135 | 13 | SimpleVariableContext vc = new SimpleVariableContext();
136 | 13 | for (Iterator i = properties.entrySet().iterator(); i.hasNext();) {
137 | 28 | Entry e = (Entry) i.next();
138 | 28 | if (!"xpath".equals(e.getKey())) {
139 | 15 | vc.setVariableValue((String) e.getKey(), e.getValue());
140 |  | }
141 |  | }
142 | 13 | xpath.setVariableContext(vc);
143 |  | }
144 |  | }
145 |  |
146 |  | }
147 |  |