Skip to content

Commit

Permalink
Initial support for records in annotation processing
Browse files Browse the repository at this point in the history
including modeling record components distinctly from parameter declarations,
since the annotation processing API cares about the distinction.

PiperOrigin-RevId: 399603892
  • Loading branch information
cushon authored and Javac Team committed Sep 29, 2021
1 parent 407dd72 commit cb60060
Show file tree
Hide file tree
Showing 17 changed files with 435 additions and 48 deletions.
23 changes: 21 additions & 2 deletions java/com/google/turbine/binder/CanonicalTypeBinder.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import com.google.turbine.binder.bound.TypeBoundClass.FieldInfo;
import com.google.turbine.binder.bound.TypeBoundClass.MethodInfo;
import com.google.turbine.binder.bound.TypeBoundClass.ParamInfo;
import com.google.turbine.binder.bound.TypeBoundClass.RecordComponentInfo;
import com.google.turbine.binder.bound.TypeBoundClass.TyVarInfo;
import com.google.turbine.binder.env.Env;
import com.google.turbine.binder.sym.ClassSymbol;
Expand Down Expand Up @@ -60,8 +61,8 @@ static SourceTypeBoundClass bind(
}
ImmutableMap<TyVarSymbol, TyVarInfo> typParamTypes =
typeParameters(base.source(), pos, env, sym, base.typeParameterTypes());
ImmutableList<ParamInfo> components =
parameters(base.source(), env, sym, pos, base.components());
ImmutableList<RecordComponentInfo> components =
components(base.source(), env, sym, pos, base.components());
ImmutableList<MethodInfo> methods = methods(base.source(), pos, env, sym, base.methods());
ImmutableList<FieldInfo> fields = fields(base.source(), env, sym, base.fields());
return new SourceTypeBoundClass(
Expand Down Expand Up @@ -166,6 +167,24 @@ private static ParamInfo param(
base.access());
}

private static ImmutableList<RecordComponentInfo> components(
SourceFile source,
Env<ClassSymbol, TypeBoundClass> env,
ClassSymbol sym,
int pos,
ImmutableList<RecordComponentInfo> components) {
ImmutableList.Builder<RecordComponentInfo> result = ImmutableList.builder();
for (RecordComponentInfo component : components) {
result.add(
new RecordComponentInfo(
component.sym(),
Canonicalize.canonicalize(source, pos, env, sym, component.type()),
component.annotations(),
component.access()));
}
return result.build();
}

private static ImmutableMap<TyVarSymbol, TyVarInfo> typeParameters(
SourceFile source,
int position,
Expand Down
13 changes: 12 additions & 1 deletion java/com/google/turbine/binder/ConstBinder.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import com.google.turbine.binder.bound.TypeBoundClass.FieldInfo;
import com.google.turbine.binder.bound.TypeBoundClass.MethodInfo;
import com.google.turbine.binder.bound.TypeBoundClass.ParamInfo;
import com.google.turbine.binder.bound.TypeBoundClass.RecordComponentInfo;
import com.google.turbine.binder.bound.TypeBoundClass.TyVarInfo;
import com.google.turbine.binder.env.CompoundEnv;
import com.google.turbine.binder.env.Env;
Expand Down Expand Up @@ -104,7 +105,7 @@ public SourceTypeBoundClass bind() {
env,
log)
.evaluateAnnotations(base.annotations());
ImmutableList<TypeBoundClass.ParamInfo> components = bindParameters(base.components());
ImmutableList<RecordComponentInfo> components = bindRecordComponents(base.components());
ImmutableList<TypeBoundClass.FieldInfo> fields = fields(base.fields());
ImmutableList<MethodInfo> methods = bindMethods(base.methods());
return new SourceTypeBoundClass(
Expand Down Expand Up @@ -169,6 +170,16 @@ private ParamInfo bindParameter(ParamInfo base) {
return new ParamInfo(base.sym(), bindType(base.type()), annos, base.access());
}

private ImmutableList<RecordComponentInfo> bindRecordComponents(
ImmutableList<RecordComponentInfo> components) {
ImmutableList.Builder<RecordComponentInfo> result = ImmutableList.builder();
for (RecordComponentInfo base : components) {
ImmutableList<AnnoInfo> annos = constEvaluator.evaluateAnnotations(base.annotations());
result.add(new RecordComponentInfo(base.sym(), bindType(base.type()), annos, base.access()));
}
return result.build();
}

static @Nullable AnnotationMetadata bindAnnotationMetadata(
TurbineTyKind kind, Iterable<AnnoInfo> annotations) {
if (kind != TurbineTyKind.ANNOTATION) {
Expand Down
24 changes: 23 additions & 1 deletion java/com/google/turbine/binder/DisambiguateTypeAnnotations.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import com.google.turbine.binder.bound.TypeBoundClass.FieldInfo;
import com.google.turbine.binder.bound.TypeBoundClass.MethodInfo;
import com.google.turbine.binder.bound.TypeBoundClass.ParamInfo;
import com.google.turbine.binder.bound.TypeBoundClass.RecordComponentInfo;
import com.google.turbine.binder.env.Env;
import com.google.turbine.binder.sym.ClassSymbol;
import com.google.turbine.diag.TurbineError;
Expand Down Expand Up @@ -73,7 +74,7 @@ public static SourceTypeBoundClass bind(
base.superClassType(),
base.typeParameterTypes(),
base.access(),
bindParameters(env, base.components(), TurbineElementType.RECORD_COMPONENT),
bindComponents(env, base.components(), TurbineElementType.RECORD_COMPONENT),
bindMethods(env, base.methods()),
bindFields(env, base.fields()),
base.owner(),
Expand Down Expand Up @@ -144,6 +145,27 @@ private static ParamInfo bindParam(
return new ParamInfo(base.sym(), type, declarationAnnotations.build(), base.access());
}

private static ImmutableList<RecordComponentInfo> bindComponents(
Env<ClassSymbol, TypeBoundClass> env,
ImmutableList<RecordComponentInfo> components,
TurbineElementType declarationTarget) {
ImmutableList.Builder<RecordComponentInfo> result = ImmutableList.builder();
for (RecordComponentInfo component : components) {
ImmutableList.Builder<AnnoInfo> declarationAnnotations = ImmutableList.builder();
Type type =
disambiguate(
env,
declarationTarget,
component.type(),
component.annotations(),
declarationAnnotations);
result.add(
new RecordComponentInfo(
component.sym(), type, declarationAnnotations.build(), component.access()));
}
return result.build();
}

/**
* Moves type annotations in {@code annotations} to {@code type}, and adds any declaration
* annotations on {@code type} to {@code declarationAnnotations}.
Expand Down
39 changes: 23 additions & 16 deletions java/com/google/turbine/binder/TypeBinder.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import com.google.turbine.binder.bound.TypeBoundClass.FieldInfo;
import com.google.turbine.binder.bound.TypeBoundClass.MethodInfo;
import com.google.turbine.binder.bound.TypeBoundClass.ParamInfo;
import com.google.turbine.binder.bound.TypeBoundClass.RecordComponentInfo;
import com.google.turbine.binder.bound.TypeBoundClass.TyVarInfo;
import com.google.turbine.binder.env.Env;
import com.google.turbine.binder.lookup.CompoundScope;
Expand All @@ -38,6 +39,7 @@
import com.google.turbine.binder.sym.FieldSymbol;
import com.google.turbine.binder.sym.MethodSymbol;
import com.google.turbine.binder.sym.ParamSymbol;
import com.google.turbine.binder.sym.RecordComponentSymbol;
import com.google.turbine.binder.sym.Symbol;
import com.google.turbine.binder.sym.TyVarSymbol;
import com.google.turbine.diag.TurbineError.ErrorKind;
Expand Down Expand Up @@ -235,8 +237,7 @@ private SourceTypeBoundClass bind() {

SyntheticMethods syntheticMethods = new SyntheticMethods();

ImmutableList<ParamInfo> components =
bindComponents(scope, syntheticMethods, base.decl().components());
ImmutableList<RecordComponentInfo> components = bindComponents(scope, base.decl().components());

ImmutableList.Builder<MethodInfo> methods =
ImmutableList.<MethodInfo>builder()
Expand Down Expand Up @@ -284,20 +285,17 @@ MethodSymbol create(ClassSymbol owner, String name) {
}
}

private ImmutableList<ParamInfo> bindComponents(
CompoundScope scope,
SyntheticMethods syntheticMethods,
ImmutableList<Tree.VarDecl> components) {
ImmutableList.Builder<ParamInfo> result = ImmutableList.builder();
private ImmutableList<RecordComponentInfo> bindComponents(
CompoundScope scope, ImmutableList<Tree.VarDecl> components) {
ImmutableList.Builder<RecordComponentInfo> result = ImmutableList.builder();
for (Tree.VarDecl p : components) {
int access = 0;
for (TurbineModifier m : p.mods()) {
access |= m.flag();
}
MethodSymbol msym = syntheticMethods.create(owner, "");
ParamInfo param =
new ParamInfo(
new ParamSymbol(msym, p.name().value()),
RecordComponentInfo param =
new RecordComponentInfo(
new RecordComponentSymbol(owner, p.name().value()),
bindTy(scope, p.ty()),
bindAnnotations(scope, p.annos()),
access);
Expand All @@ -308,7 +306,7 @@ private ImmutableList<ParamInfo> bindComponents(

/** Collect synthetic and implicit methods, including default constructors and enum methods. */
ImmutableList<MethodInfo> syntheticMethods(
SyntheticMethods syntheticMethods, ImmutableList<ParamInfo> components) {
SyntheticMethods syntheticMethods, ImmutableList<RecordComponentInfo> components) {
switch (base.kind()) {
case CLASS:
return maybeDefaultConstructor(syntheticMethods);
Expand All @@ -322,13 +320,22 @@ ImmutableList<MethodInfo> syntheticMethods(
}

private ImmutableList<MethodInfo> maybeDefaultRecordConstructor(
SyntheticMethods syntheticMethods, ImmutableList<ParamInfo> components) {
SyntheticMethods syntheticMethods, ImmutableList<RecordComponentInfo> components) {
if (hasConstructor()) {
return ImmutableList.of();
}
MethodSymbol symbol = syntheticMethods.create(owner, "<init>");
ImmutableList.Builder<ParamInfo> params = ImmutableList.builder();
for (RecordComponentInfo component : components) {
params.add(
new ParamInfo(
new ParamSymbol(symbol, component.name()),
component.type(),
component.annotations(),
component.access()));
}
return ImmutableList.of(
syntheticConstructor(symbol, components, TurbineVisibility.fromAccess(base.access())));
syntheticConstructor(symbol, params.build(), TurbineVisibility.fromAccess(base.access())));
}

private ImmutableList<MethodInfo> maybeDefaultConstructor(SyntheticMethods syntheticMethods) {
Expand Down Expand Up @@ -450,7 +457,7 @@ private ImmutableList<MethodInfo> syntheticEnumMethods(SyntheticMethods syntheti
}

private ImmutableList<MethodInfo> syntheticRecordMethods(
SyntheticMethods syntheticMethods, ImmutableList<ParamInfo> components) {
SyntheticMethods syntheticMethods, ImmutableList<RecordComponentInfo> components) {
ImmutableList.Builder<MethodInfo> methods = ImmutableList.builder();
MethodSymbol toStringMethod = syntheticMethods.create(owner, "toString");
methods.add(
Expand Down Expand Up @@ -496,7 +503,7 @@ private ImmutableList<MethodInfo> syntheticRecordMethods(
null,
ImmutableList.of(),
null));
for (ParamInfo c : components) {
for (RecordComponentInfo c : components) {
MethodSymbol componentMethod = syntheticMethods.create(owner, c.name());
methods.add(
new MethodInfo(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public class SourceTypeBoundClass implements TypeBoundClass {
private final ImmutableMap<TyVarSymbol, TyVarInfo> typeParameterTypes;
private final @Nullable Type superClassType;
private final ImmutableList<Type> interfaceTypes;
private final ImmutableList<ParamInfo> components;
private final ImmutableList<RecordComponentInfo> components;
private final ImmutableList<MethodInfo> methods;
private final ImmutableList<FieldInfo> fields;
private final CompoundScope enclosingScope;
Expand All @@ -60,7 +60,7 @@ public SourceTypeBoundClass(
@Nullable Type superClassType,
ImmutableMap<TyVarSymbol, TyVarInfo> typeParameterTypes,
int access,
ImmutableList<ParamInfo> components,
ImmutableList<RecordComponentInfo> components,
ImmutableList<MethodInfo> methods,
ImmutableList<FieldInfo> fields,
@Nullable ClassSymbol owner,
Expand Down Expand Up @@ -154,7 +154,7 @@ public ImmutableList<Type> interfaceTypes() {

/** The record components. */
@Override
public ImmutableList<ParamInfo> components() {
public ImmutableList<RecordComponentInfo> components() {
return components;
}

Expand Down
44 changes: 43 additions & 1 deletion java/com/google/turbine/binder/bound/TypeBoundClass.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import com.google.turbine.binder.sym.FieldSymbol;
import com.google.turbine.binder.sym.MethodSymbol;
import com.google.turbine.binder.sym.ParamSymbol;
import com.google.turbine.binder.sym.RecordComponentSymbol;
import com.google.turbine.binder.sym.TyVarSymbol;
import com.google.turbine.model.Const;
import com.google.turbine.model.TurbineFlag;
Expand Down Expand Up @@ -51,7 +52,7 @@ public interface TypeBoundClass extends HeaderBoundClass {
ImmutableList<MethodInfo> methods();

/** Record components. */
ImmutableList<ParamInfo> components();
ImmutableList<RecordComponentInfo> components();

/**
* Annotation metadata, e.g. from {@link java.lang.annotation.Target}, {@link
Expand Down Expand Up @@ -322,4 +323,45 @@ public int access() {
return access;
}
}

/** A record component. */
class RecordComponentInfo {
private final RecordComponentSymbol sym;
private final Type type;
private final int access;
private final ImmutableList<AnnoInfo> annotations;

public RecordComponentInfo(
RecordComponentSymbol sym, Type type, ImmutableList<AnnoInfo> annotations, int access) {
this.sym = sym;
this.type = type;
this.access = access;
this.annotations = annotations;
}

/** The record component's symbol. */
public RecordComponentSymbol sym() {
return sym;
}

/** The record component type. */
public Type type() {
return type;
}

/** Record component annotations. */
public ImmutableList<AnnoInfo> annotations() {
return annotations;
}

/** The Record component's name. */
public String name() {
return sym.name();
}

/** The Record component's modifiers. */
public int access() {
return access;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,7 @@ public ImmutableList<MethodInfo> methods() {
}

@Override
public ImmutableList<ParamInfo> components() {
public ImmutableList<RecordComponentInfo> components() {
return ImmutableList.of();
}

Expand Down
67 changes: 67 additions & 0 deletions java/com/google/turbine/binder/sym/RecordComponentSymbol.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Copyright 2021 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.turbine.binder.sym;

import com.google.errorprone.annotations.Immutable;
import java.util.Objects;
import org.jspecify.nullness.Nullable;

/** A record component symbol. */
@Immutable
public class RecordComponentSymbol implements Symbol {
private final ClassSymbol owner;
private final String name;

public RecordComponentSymbol(ClassSymbol owner, String name) {
this.owner = owner;
this.name = name;
}

/** The enclosing class. */
public ClassSymbol owner() {
return owner;
}

/** The parameter name. */
public String name() {
return name;
}

@Override
public Kind symKind() {
return Kind.RECORD_COMPONENT;
}

@Override
public int hashCode() {
return Objects.hash(name, owner);
}

@Override
public boolean equals(@Nullable Object obj) {
if (!(obj instanceof RecordComponentSymbol)) {
return false;
}
RecordComponentSymbol other = (RecordComponentSymbol) obj;
return name().equals(other.name()) && owner().equals(other.owner());
}

@Override
public String toString() {
return name;
}
}
Loading

0 comments on commit cb60060

Please sign in to comment.