]> WPIA git - gigi.git/blob - util-testing/org/cacert/gigi/localisation/TranslationCollectingVisitor.java
fix: print error messages for translation extraction to stderr
[gigi.git] / util-testing / org / cacert / gigi / localisation / TranslationCollectingVisitor.java
1 package org.cacert.gigi.localisation;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.lang.reflect.Method;
6 import java.util.Stack;
7
8 import org.eclipse.jdt.internal.compiler.ASTVisitor;
9 import org.eclipse.jdt.internal.compiler.ast.AllocationExpression;
10 import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
11 import org.eclipse.jdt.internal.compiler.ast.ConditionalExpression;
12 import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
13 import org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall;
14 import org.eclipse.jdt.internal.compiler.ast.Expression;
15 import org.eclipse.jdt.internal.compiler.ast.MessageSend;
16 import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
17 import org.eclipse.jdt.internal.compiler.ast.NullLiteral;
18 import org.eclipse.jdt.internal.compiler.ast.QualifiedAllocationExpression;
19 import org.eclipse.jdt.internal.compiler.ast.StringLiteral;
20 import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
21 import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
22 import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
23 import org.eclipse.jdt.internal.compiler.util.Util;
24
25 public final class TranslationCollectingVisitor extends ASTVisitor {
26
27     MethodBinding cm;
28
29     private CompilationUnitDeclaration unit;
30
31     TaintSource[] ts;
32
33     private TranslationCollector translationCollector;
34
35     Stack<QualifiedAllocationExpression> anonymousConstructorCall = new Stack<>();
36
37     private boolean hadErrors = false;
38
39     public boolean hadErrors() {
40         return hadErrors;
41     }
42
43     public TranslationCollectingVisitor(CompilationUnitDeclaration unit, TaintSource[] target, TranslationCollector c) {
44         this.unit = unit;
45         ts = target;
46         this.translationCollector = c;
47     }
48
49     @Override
50     public boolean visit(MethodDeclaration methodDeclaration, org.eclipse.jdt.internal.compiler.lookup.ClassScope scope) {
51         cm = methodDeclaration.binding;
52         return true;
53     }
54
55     @Override
56     public void endVisit(MethodDeclaration methodDeclaration, org.eclipse.jdt.internal.compiler.lookup.ClassScope scope) {
57         cm = null;
58     }
59
60     @Override
61     public boolean visit(ConstructorDeclaration constructorDeclaration, ClassScope scope) {
62         cm = constructorDeclaration.binding;
63         return super.visit(constructorDeclaration, scope);
64     }
65
66     @Override
67     public void endVisit(ConstructorDeclaration constructorDeclaration, ClassScope scope) {
68         cm = null;
69     }
70
71     @Override
72     public boolean visit(AllocationExpression allocationExpression, BlockScope scope) {
73         TaintSource test = new TaintSource(allocationExpression.binding);
74         for (TaintSource taintSource : ts) {
75             if (taintSource.equals(test)) {
76                 check(null, scope, allocationExpression.arguments[taintSource.getTgt()], allocationExpression.toString());
77                 return true;
78             }
79         }
80         return super.visit(allocationExpression, scope);
81     }
82
83     @Override
84     public boolean visit(QualifiedAllocationExpression qualifiedAllocationExpression, BlockScope scope) {
85         anonymousConstructorCall.push(qualifiedAllocationExpression);
86         return super.visit(qualifiedAllocationExpression, scope);
87     }
88
89     @Override
90     public void endVisit(QualifiedAllocationExpression qualifiedAllocationExpression, BlockScope scope) {
91         if (anonymousConstructorCall.pop() != qualifiedAllocationExpression) {
92             throw new Error("stack illegally manipulated");
93         }
94     }
95
96     @Override
97     public boolean visit(ExplicitConstructorCall explicitConstructor, BlockScope scope) {
98
99         TaintSource t = new TaintSource(explicitConstructor.binding);
100
101         for (TaintSource t0 : ts) {
102             if (t0.equals(t)) {
103                 Expression[] ags = explicitConstructor.arguments;
104                 if (anonymousConstructorCall.size() > 0) {
105                     ags = anonymousConstructorCall.peek().arguments;
106                 }
107                 if (ags == null) {
108                     System.err.println(explicitConstructor);
109                     return true;
110                 }
111                 Expression e = ags[t0.getTgt()];
112                 check(null, scope, e, explicitConstructor.toString());
113                 break;
114             }
115         }
116         return super.visit(explicitConstructor, scope);
117     }
118
119     @Override
120     public boolean visit(org.eclipse.jdt.internal.compiler.ast.MessageSend call, org.eclipse.jdt.internal.compiler.lookup.BlockScope scope) {
121         if (call.binding == null) {
122             System.err.println("Unbound:" + call + " in " + call.sourceStart());
123             return true;
124         }
125         // System.out.println("Message");
126         TaintSource t = new TaintSource(call.binding);
127
128         for (TaintSource t0 : ts) {
129             if (t0.equals(t)) {
130                 Expression[] ags = call.arguments;
131                 if (ags == null) {
132                     System.err.println(call);
133                     return true;
134                 }
135                 Expression e = ags[t0.getTgt()];
136                 check(call, scope, e, call.toString());
137                 break;
138             }
139         }
140         return true;
141     }
142
143     private void check(org.eclipse.jdt.internal.compiler.ast.MessageSend call, org.eclipse.jdt.internal.compiler.lookup.BlockScope scope, Expression e, String caller) {
144         if (e instanceof StringLiteral) {
145             int[] lineEnds = null;
146             int lineNumber = Util.getLineNumber(e.sourceStart, lineEnds = unit.compilationResult.getLineSeparatorPositions(), 0, lineEnds.length - 1);
147
148             String content = new String(((StringLiteral) e).source());
149             File f0 = new File(new String(unit.compilationResult.fileName)).getAbsoluteFile();
150             File f2 = translationCollector.base.getAbsoluteFile();
151             try {
152                 translationCollector.add(content, f0.getCanonicalPath().substring(f2.getCanonicalPath().length() + 1) + ":" + lineNumber);
153             } catch (IOException e1) {
154                 e1.printStackTrace();
155             }
156             return;
157         }
158
159         if (e instanceof NullLiteral) {
160             return;
161         }
162
163         if (e instanceof MessageSend) {
164             MessageSend m2 = (MessageSend) e;
165             TaintSource ts = new TaintSource(m2.binding);
166             if (ts.equals(new TaintSource("org.cacert.gigi.pages", "Page", "getTitle()", 0))) {
167                 return;
168             }
169             if (m2.receiver.resolvedType.isCompatibleWith(scope.getJavaLangEnum())) {
170                 testEnum(m2.receiver, m2.binding);
171                 System.err.println("ENUM-SRC: !" + m2.receiver);
172             }
173         }
174         if (e.resolvedType.isCompatibleWith(scope.getJavaLangEnum())) {
175             // TODO ?
176             System.err.println("ENUM-Not-Hanled");
177         }
178
179         TaintSource b = cm == null ? null : new TaintSource(cm);
180         for (TaintSource taintSource : ts) {
181             if (taintSource.equals(b) || (taintSource.getMaskOnly() != null && taintSource.getMaskOnly().equals(b))) {
182                 return;
183             }
184         }
185         if (e instanceof ConditionalExpression) {
186             check(call, scope, ((ConditionalExpression) e).valueIfFalse, caller);
187             check(call, scope, ((ConditionalExpression) e).valueIfTrue, caller);
188             return;
189         }
190
191         System.err.println();
192
193         System.err.println(new String(scope.enclosingClassScope().referenceType().compilationResult.fileName));
194         System.err.println("Cannot Handle: " + e + " in " + (call == null ? "constructor" : call.sourceStart) + " => " + caller);
195         System.err.println(e.getClass());
196         System.err.println("To ignore: " + (b == null ? "don't know" : b.toConfLine()));
197         hadErrors = true;
198     }
199
200     private void testEnum(Expression e, MethodBinding binding) {
201         if (binding.parameters.length != 0) {
202             System.err.println("ERROR: meth");
203             return;
204         }
205         System.err.println(e.resolvedType.getClass());
206         String s2 = new String(e.resolvedType.qualifiedPackageName()) + "." + (new String(e.resolvedType.qualifiedSourceName()).replace('.', '$'));
207         try {
208             Class<?> c = Class.forName(s2);
209             Enum<?>[] e1 = (Enum[]) c.getMethod("values").invoke(null);
210             Method m = c.getMethod(new String(binding.selector));
211             for (int j = 0; j < e1.length; j++) {
212                 System.err.println(m.invoke(e1[j]));
213             }
214         } catch (ClassNotFoundException e1) {
215             e1.printStackTrace();
216         } catch (ReflectiveOperationException e1) {
217             e1.printStackTrace();
218         }
219         System.err.println("ENUM-done: " + e + "!");
220         return;
221     }
222 }