Skip to content

Commit 440f9b7

Browse files
committed
Created DetailedEqualityScanner for providing more in-depth error reporting inside Compile Testing's generatesSources()
------------- Created by MOE: http://code.google.com/p/moe-java MOE_MIGRATED_REVID=66117067
1 parent cf9d650 commit 440f9b7

15 files changed

+2672
-96
lines changed
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
/*
2+
* Copyright (C) 2014 Google, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.google.testing.compile;
17+
18+
import com.google.common.base.Function;
19+
import com.google.common.base.Joiner;
20+
import com.google.common.collect.FluentIterable;
21+
import com.google.common.collect.Lists;
22+
23+
import com.sun.source.tree.BlockTree;
24+
import com.sun.source.tree.BreakTree;
25+
import com.sun.source.tree.ClassTree;
26+
import com.sun.source.tree.ContinueTree;
27+
import com.sun.source.tree.IdentifierTree;
28+
import com.sun.source.tree.ImportTree;
29+
import com.sun.source.tree.LabeledStatementTree;
30+
import com.sun.source.tree.LiteralTree;
31+
import com.sun.source.tree.MemberSelectTree;
32+
import com.sun.source.tree.MethodTree;
33+
import com.sun.source.tree.ModifiersTree;
34+
import com.sun.source.tree.PrimitiveTypeTree;
35+
import com.sun.source.tree.Tree;
36+
import com.sun.source.tree.TypeParameterTree;
37+
import com.sun.source.tree.VariableTree;
38+
import com.sun.source.util.SimpleTreeVisitor;
39+
import com.sun.source.util.TreePath;
40+
41+
import java.util.List;
42+
43+
/**
44+
* This class contains methods for providing breadcrumb {@code String}s which describe the contents
45+
* of a {@code TreePath}.
46+
*
47+
* @author Stephen Pratt
48+
*/
49+
final class Breadcrumbs {
50+
private static final BreadcrumbVisitor BREADCRUMB_VISITOR = new BreadcrumbVisitor();
51+
private Breadcrumbs() {}
52+
53+
/**
54+
* Returns a string describing the {@link TreePath} given.
55+
*/
56+
static String describeTreePath(TreePath path) {
57+
// TODO(spratt) The number of extra strings this creates by building a list of strings,
58+
// and then joining it is at least a little wasteful. Consider modifying the BreadcrumbVisitor
59+
// to take a StringBuilder and traverse the whole path.
60+
return Joiner.on("->").join(getBreadcrumbList(path));
61+
}
62+
63+
/**
64+
* Returns a list of breadcrumb strings describing the {@link TreePath} given.
65+
*/
66+
static List<String> getBreadcrumbList(TreePath path) {
67+
return Lists.reverse(FluentIterable.from(path)
68+
.transform(new Function<Tree, String>() {
69+
@Override public String apply(Tree t) {
70+
return t.accept(BREADCRUMB_VISITOR, null);
71+
}
72+
}).toList());
73+
}
74+
75+
/**
76+
* A {@link SimpleTreeVisitor} for providing a breadcrumb {@code String} for a {@link Tree} node.
77+
* The breadcrumb {@code String} will not be unique, but can be used to give context about the
78+
* node as it exists within a {@code TreePath}.
79+
*/
80+
@SuppressWarnings("restriction") // Sun APIs usage intended
81+
static final class BreadcrumbVisitor extends SimpleTreeVisitor<String, Void> {
82+
83+
/** Returns a {@code String} describing the {@code Tree.Kind} of the given {@code Tree}. */
84+
private String kindString(Tree t) {
85+
return t.getKind().toString();
86+
}
87+
88+
/**
89+
* Returns a {@code String} describing the {@code Tree.Kind} of the given {@code Tree}.
90+
* The string will be specified by the {@code toString()} value of the detail object given.
91+
*/
92+
private String detailedKindString(Tree t, Object detail) {
93+
return String.format("%s(%s)", kindString(t), detail);
94+
}
95+
96+
@Override
97+
public String defaultAction(Tree t, Void v) {
98+
return (t != null) ? kindString(t) : "";
99+
}
100+
101+
@Override
102+
public String visitBlock(BlockTree reference, Void v) {
103+
return (reference != null)
104+
? detailedKindString(reference, reference.isStatic() ? "static" : "non-static") : "";
105+
}
106+
107+
@Override
108+
public String visitBreak(BreakTree reference, Void v) {
109+
return (reference != null) ? detailedKindString(reference, reference.getLabel()) : "";
110+
}
111+
112+
@Override
113+
public String visitClass(ClassTree reference, Void v) {
114+
return (reference != null) ? detailedKindString(reference, reference.getSimpleName()) : "";
115+
}
116+
117+
@Override
118+
public String visitContinue(ContinueTree reference, Void v) {
119+
return (reference != null) ? detailedKindString(reference, reference.getLabel()) : "";
120+
}
121+
122+
@Override
123+
public String visitIdentifier(IdentifierTree reference, Void v) {
124+
return (reference != null) ? detailedKindString(reference, reference.getName()) : "";
125+
}
126+
127+
@Override
128+
public String visitImport(ImportTree reference, Void v) {
129+
return (reference != null) ?
130+
detailedKindString(reference, reference.isStatic() ? "static" : "non-static") : "";
131+
}
132+
133+
@Override
134+
public String visitLabeledStatement(LabeledStatementTree reference, Void v) {
135+
return (reference != null) ? detailedKindString(reference, reference.getLabel()) : "";
136+
}
137+
138+
@Override
139+
public String visitLiteral(LiteralTree reference, Void v) {
140+
return (reference != null) ? detailedKindString(reference, reference.getValue()) : "";
141+
}
142+
143+
@Override
144+
public String visitMethod(MethodTree reference, Void v) {
145+
return (reference != null) ? detailedKindString(reference, reference.getName()) : "";
146+
}
147+
148+
@Override
149+
public String visitModifiers(ModifiersTree reference, Void v) {
150+
return (reference != null) ? detailedKindString(reference, reference.getFlags()) : "";
151+
}
152+
153+
@Override
154+
public String visitMemberSelect(MemberSelectTree reference, Void v) {
155+
return (reference != null) ? detailedKindString(reference, reference.getIdentifier()) : "";
156+
}
157+
158+
@Override
159+
public String visitPrimitiveType(PrimitiveTypeTree reference, Void v) {
160+
return (reference != null)
161+
? detailedKindString(reference, reference.getPrimitiveTypeKind()) : "";
162+
}
163+
164+
@Override
165+
public String visitTypeParameter(TypeParameterTree reference, Void v) {
166+
return (reference != null) ? detailedKindString(reference, reference.getName()) : "";
167+
}
168+
169+
@Override
170+
public String visitVariable(VariableTree reference, Void v) {
171+
return (reference != null) ? detailedKindString(reference, reference.getName()) : "";
172+
}
173+
}
174+
}

src/main/java/com/google/testing/compile/Compilation.java

Lines changed: 60 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
import com.sun.source.tree.CompilationUnitTree;
2929
import com.sun.source.util.JavacTask;
30+
import com.sun.source.util.Trees;
3031
import com.sun.tools.javac.api.JavacTool;
3132

3233
import java.io.IOException;
@@ -70,16 +71,15 @@ static Result compile(Iterable<? extends Processor> processors,
7071
sources);
7172
task.setProcessors(processors);
7273
boolean successful = task.call();
73-
return new Result(successful, diagnosticCollector.getDiagnostics(),
74+
return new Result(successful, sortDiagnosticsByKind(diagnosticCollector.getDiagnostics()),
7475
fileManager.getOutputFiles());
7576
}
7677

7778
/**
7879
* Parse {@code sources} into {@linkplain CompilationUnitTree compilation units}. This method
7980
* <b>does not</b> compile the sources.
8081
*/
81-
static Iterable<? extends CompilationUnitTree> parse(
82-
Iterable<? extends JavaFileObject> sources) {
82+
static ParseResult parse(Iterable<? extends JavaFileObject> sources) {
8383
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
8484
DiagnosticCollector<JavaFileObject> diagnosticCollector =
8585
new DiagnosticCollector<JavaFileObject>();
@@ -101,37 +101,80 @@ static Iterable<? extends CompilationUnitTree> parse(
101101
+ Diagnostics.toString(diagnostics));
102102
}
103103
}
104-
return parsedCompilationUnits;
104+
return new ParseResult(sortDiagnosticsByKind(diagnostics), parsedCompilationUnits,
105+
Trees.instance(task));
105106
} catch (IOException e) {
106107
throw new RuntimeException(e);
107108
}
108109
}
109110

111+
private static ImmutableListMultimap<Diagnostic.Kind, Diagnostic<? extends JavaFileObject>>
112+
sortDiagnosticsByKind(Iterable<Diagnostic<? extends JavaFileObject>> diagnostics) {
113+
return Multimaps.index(diagnostics,
114+
new Function<Diagnostic<?>, Diagnostic.Kind>() {
115+
@Override public Diagnostic.Kind apply(Diagnostic<?> input) {
116+
return input.getKind();
117+
}
118+
});
119+
}
120+
121+
/**
122+
* The diagnostic, parse trees, and {@link Trees} instance for a parse task.
123+
*
124+
* <p>Note: It is possible for the {@link Trees} instance contained within a {@code ParseResult}
125+
* to be invalidated by a call to {@link com.sun.tools.javac.api.JavacTaskImpl#cleanup()}. Though
126+
* we do not currently expose the {@link JavacTask} used to create a {@code ParseResult} to
127+
* {@code cleanup()} calls on its underlying implementation, this should be acknowledged as an
128+
* implementation detail that could cause unexpected behavior when making calls to methods in
129+
* {@link Trees}.
130+
*/
131+
static final class ParseResult {
132+
private final ImmutableListMultimap<Diagnostic.Kind, Diagnostic<? extends JavaFileObject>>
133+
diagnostics;
134+
private final ImmutableList<? extends CompilationUnitTree> compilationUnits;
135+
private final Trees trees;
136+
137+
ParseResult(
138+
ImmutableListMultimap<Diagnostic.Kind, Diagnostic<? extends JavaFileObject>> diagnostics,
139+
Iterable<? extends CompilationUnitTree> compilationUnits, Trees trees) {
140+
this.trees = trees;
141+
this.compilationUnits = ImmutableList.copyOf(compilationUnits);
142+
this.diagnostics = diagnostics;
143+
}
144+
145+
ImmutableListMultimap<Diagnostic.Kind, Diagnostic<? extends JavaFileObject>>
146+
diagnosticsByKind() {
147+
return diagnostics;
148+
}
149+
150+
Iterable<? extends CompilationUnitTree> compilationUnits() {
151+
return compilationUnits;
152+
}
153+
154+
Trees trees() {
155+
return trees;
156+
}
157+
}
158+
110159
/** The diagnostic and file output of a compilation. */
111160
static final class Result {
112161
private final boolean successful;
113162
private final ImmutableListMultimap<Diagnostic.Kind, Diagnostic<? extends JavaFileObject>>
114-
diagnosticsByKind;
163+
diagnostics;
115164
private final ImmutableListMultimap<JavaFileObject.Kind, JavaFileObject> generatedFilesByKind;
116165

117-
Result(
118-
boolean successful,
119-
Iterable<Diagnostic<? extends JavaFileObject>> diagnostics,
166+
Result(boolean successful,
167+
ImmutableListMultimap<Diagnostic.Kind, Diagnostic<? extends JavaFileObject>> diagnostics,
120168
Iterable<JavaFileObject> generatedFiles) {
121169
this.successful = successful;
122-
this.diagnosticsByKind = Multimaps.index(diagnostics,
123-
new Function<Diagnostic<?>, Diagnostic.Kind>() {
124-
@Override public Diagnostic.Kind apply(Diagnostic<?> input) {
125-
return input.getKind();
126-
}
127-
});
170+
this.diagnostics = diagnostics;
128171
this.generatedFilesByKind = Multimaps.index(generatedFiles,
129172
new Function<JavaFileObject, JavaFileObject.Kind>() {
130173
@Override public JavaFileObject.Kind apply(JavaFileObject input) {
131174
return input.getKind();
132175
}
133176
});
134-
if (!successful && diagnosticsByKind.get(Diagnostic.Kind.ERROR).isEmpty()) {
177+
if (!successful && diagnostics.get(Diagnostic.Kind.ERROR).isEmpty()) {
135178
throw new CompilationFailureException();
136179
}
137180
}
@@ -142,7 +185,7 @@ boolean successful() {
142185

143186
ImmutableListMultimap<Diagnostic.Kind, Diagnostic<? extends JavaFileObject>>
144187
diagnosticsByKind() {
145-
return diagnosticsByKind;
188+
return diagnostics;
146189
}
147190

148191
ImmutableListMultimap<JavaFileObject.Kind, JavaFileObject> generatedFilesByKind() {
@@ -157,7 +200,7 @@ ImmutableList<JavaFileObject> generatedSources() {
157200
public String toString() {
158201
return Objects.toStringHelper(this)
159202
.add("successful", successful)
160-
.add("diagnostics", diagnosticsByKind)
203+
.add("diagnostics", diagnostics)
161204
.toString();
162205
}
163206
}

src/main/java/com/google/testing/compile/JavaFileObjects.java

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,13 @@
1919
import static com.google.common.base.Preconditions.checkNotNull;
2020
import static javax.tools.JavaFileObject.Kind.SOURCE;
2121

22+
import com.google.common.base.CharMatcher;
23+
import com.google.common.base.Joiner;
24+
import com.google.common.base.Splitter;
25+
import com.google.common.collect.ImmutableList;
26+
import com.google.common.io.ByteSource;
27+
import com.google.common.io.Resources;
28+
2229
import java.io.ByteArrayInputStream;
2330
import java.io.IOException;
2431
import java.io.InputStream;
@@ -29,19 +36,13 @@
2936
import java.net.URI;
3037
import java.net.URL;
3138
import java.nio.charset.Charset;
39+
import java.util.Arrays;
3240

3341
import javax.tools.ForwardingJavaFileObject;
3442
import javax.tools.JavaFileObject;
3543
import javax.tools.JavaFileObject.Kind;
3644
import javax.tools.SimpleJavaFileObject;
3745

38-
import com.google.common.base.CharMatcher;
39-
import com.google.common.base.Joiner;
40-
import com.google.common.base.Splitter;
41-
import com.google.common.collect.ImmutableList;
42-
import com.google.common.io.ByteSource;
43-
import com.google.common.io.Resources;
44-
4546
/**
4647
* A utility class for creating {@link JavaFileObject} instances.
4748
*
@@ -79,6 +80,11 @@ public static JavaFileObject forSourceString(String fullyQualifiedName, String s
7980
* }</pre>
8081
*/
8182
public static JavaFileObject forSourceLines(String fullyQualifiedName, String... lines) {
83+
return forSourceLines(fullyQualifiedName, Arrays.asList(lines));
84+
}
85+
86+
/** An overload of {@code #forSourceLines} that takes an {@code Iterable<String>}. */
87+
public static JavaFileObject forSourceLines(String fullyQualifiedName, Iterable<String> lines) {
8288
return forSourceString(fullyQualifiedName, LINE_JOINER.join(lines));
8389
}
8490

0 commit comments

Comments
 (0)