Skip to content

Commit 53b37fe

Browse files
author
Vicente Romero
committed
8288130: compiler error with AP and explicit record accessor
Reviewed-by: jlahoda
1 parent 0828881 commit 53b37fe

File tree

5 files changed

+229
-184
lines changed

5 files changed

+229
-184
lines changed

src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1503,30 +1503,25 @@ public RecordComponent getRecordComponent(VarSymbol field) {
15031503
return null;
15041504
}
15051505

1506-
public RecordComponent getRecordComponent(JCVariableDecl var, boolean addIfMissing, List<JCAnnotation> annotations) {
1506+
/* creates a record component if non is related to the given variable and recreates a brand new one
1507+
* in other case
1508+
*/
1509+
public RecordComponent createRecordComponent(JCVariableDecl var, List<JCAnnotation> annotations) {
15071510
RecordComponent toRemove = null;
15081511
for (RecordComponent rc : recordComponents) {
15091512
/* it could be that a record erroneously declares two record components with the same name, in that
15101513
* case we need to use the position to disambiguate
15111514
*/
15121515
if (rc.name == var.name && var.pos == rc.pos) {
1513-
if (rc.type.hasTag(TypeTag.ERROR) && !var.sym.type.hasTag(TypeTag.ERROR)) {
1514-
// Found a record component with an erroneous type: save it so that it can be removed later.
1515-
// If the class type of the record component is generated by annotation processor, it should
1516-
// use the new actual class type and symbol instead of the old dummy ErrorType.
1517-
toRemove = rc;
1518-
} else {
1519-
// Found a good record component: just return.
1520-
return rc;
1521-
}
1516+
toRemove = rc;
15221517
}
15231518
}
15241519
RecordComponent rc = null;
15251520
if (toRemove != null) {
15261521
// Found a record component with an erroneous type: remove it and create a new one
15271522
recordComponents = List.filter(recordComponents, toRemove);
1528-
recordComponents = recordComponents.append(rc = new RecordComponent(var.sym, annotations));
1529-
} else if (addIfMissing) {
1523+
recordComponents = recordComponents.append(rc = new RecordComponent(var.sym, toRemove.originalAnnos, toRemove.isVarargs));
1524+
} else {
15301525
// Didn't find the record component: create one.
15311526
recordComponents = recordComponents.append(rc = new RecordComponent(var.sym, annotations));
15321527
}
@@ -1809,6 +1804,10 @@ public RecordComponent(Name name, Type type, Symbol owner) {
18091804
}
18101805

18111806
public RecordComponent(VarSymbol field, List<JCAnnotation> annotations) {
1807+
this(field, annotations, field.type.hasTag(TypeTag.ARRAY) && ((ArrayType)field.type).isVarargs());
1808+
}
1809+
1810+
public RecordComponent(VarSymbol field, List<JCAnnotation> annotations, boolean isVarargs) {
18121811
super(PUBLIC, field.name, field.type, field.owner);
18131812
this.originalAnnos = annotations;
18141813
this.pos = field.pos;
@@ -1817,7 +1816,7 @@ public RecordComponent(VarSymbol field, List<JCAnnotation> annotations) {
18171816
* the symbol will be blown out and we won't be able to know if the original
18181817
* record component was declared varargs or not.
18191818
*/
1820-
this.isVarargs = type.hasTag(TypeTag.ARRAY) && ((ArrayType)type).isVarargs();
1819+
this.isVarargs = isVarargs;
18211820
}
18221821

18231822
public List<JCAnnotation> getOriginalAnnos() { return originalAnnos; }

src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2960,6 +2960,9 @@ public void validateTypeAnnotations(List<JCAnnotation> annotations, boolean isTy
29602960
/** Check an annotation of a symbol.
29612961
*/
29622962
private void validateAnnotation(JCAnnotation a, JCTree declarationTree, Symbol s) {
2963+
/** NOTE: if annotation processors are present, annotation processing rounds can happen after this method,
2964+
* this can impact in particular records for which annotations are forcibly propagated.
2965+
*/
29632966
validateAnnotationTree(a);
29642967
boolean isRecordMember = ((s.flags_field & RECORD) != 0 || s.enclClass() != null && s.enclClass().isRecord());
29652968

src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -983,7 +983,7 @@ protected void runPhase(Env<AttrContext> env) {
983983
List<JCVariableDecl> fields = TreeInfo.recordFields(tree);
984984
memberEnter.memberEnter(fields, env);
985985
for (JCVariableDecl field : fields) {
986-
sym.getRecordComponent(field, true,
986+
sym.createRecordComponent(field,
987987
field.mods.annotations.isEmpty() ?
988988
List.nil() :
989989
new TreeCopier<JCTree>(make.at(field.pos)).copy(field.mods.annotations));
@@ -1229,10 +1229,37 @@ private void addRecordMembersIfNeeded(JCClassDecl tree, Env<AttrContext> env) {
12291229
memberEnter.memberEnter(equals, env);
12301230
}
12311231

1232-
// fields can't be varargs, lets remove the flag
1232+
/** Some notes regarding the code below. Annotations applied to elements of a record header are propagated
1233+
* to other elements which, when applicable, not explicitly declared by the user: the canonical constructor,
1234+
* accessors, fields and record components. Of all these the only ones that can't be explicitly declared are
1235+
* the fields and the record components.
1236+
*
1237+
* Now given that annotations are propagated to all possible targets regardless of applicability,
1238+
* annotations not applicable to a given element should be removed. See Check::validateAnnotation. Once
1239+
* annotations are removed we could lose the whole picture, that's why original annotations are stored in
1240+
* the record component, see RecordComponent::originalAnnos, but there is no real AST representing a record
1241+
* component so if there is an annotation processing round it could be that we need to reenter a record for
1242+
* which we need to re-attribute its annotations. This is why one of the things the code below is doing is
1243+
* copying the original annotations from the record component to the corresponding field, again this applies
1244+
* only if APs are present.
1245+
*
1246+
* We need to copy the annotations to the field so that annotations applicable only to the record component
1247+
* can be attributed as if declared in the field and then stored in the metadata associated to the record
1248+
* component.
1249+
*/
12331250
List<JCVariableDecl> recordFields = TreeInfo.recordFields(tree);
12341251
for (JCVariableDecl field: recordFields) {
1252+
RecordComponent rec = tree.sym.getRecordComponent(field.sym);
1253+
TreeCopier<JCTree> tc = new TreeCopier<>(make.at(field.pos));
1254+
List<JCAnnotation> originalAnnos = tc.copy(rec.getOriginalAnnos());
1255+
12351256
field.mods.flags &= ~Flags.VARARGS;
1257+
if (originalAnnos.length() != field.mods.annotations.length()) {
1258+
field.mods.annotations = originalAnnos;
1259+
annotate.annotateLater(originalAnnos, env, field.sym, field.pos());
1260+
}
1261+
1262+
// also here
12361263
field.sym.flags_field &= ~Flags.VARARGS;
12371264
}
12381265
// now lets add the accessors

src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,8 @@ public <T extends JCTree> List<T> copy(List<T> trees) {
6565
}
6666

6767
public <T extends JCTree> List<T> copy(List<T> trees, P p) {
68-
if (trees == null)
69-
return null;
68+
if (trees == null || trees.isEmpty())
69+
return trees;
7070
ListBuffer<T> lb = new ListBuffer<>();
7171
for (T tree: trees)
7272
lb.append(copy(tree, p));

0 commit comments

Comments
 (0)