diff --git a/src/main/java/com/google/api/generator/engine/ast/SuperObjectValue.java b/src/main/java/com/google/api/generator/engine/ast/SuperObjectValue.java new file mode 100644 index 0000000000..973f6c1d91 --- /dev/null +++ b/src/main/java/com/google/api/generator/engine/ast/SuperObjectValue.java @@ -0,0 +1,55 @@ +// Copyright 2020 Google LLC +// +// 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.api.generator.engine.ast; + +import com.google.auto.value.AutoValue; +import com.google.common.base.Preconditions; + +@AutoValue +public abstract class SuperObjectValue implements ObjectValue { + private static final String SUPER_VALUE = "super"; + + @Override + public abstract TypeNode type(); + + @Override + public String value() { + return SUPER_VALUE; + } + + // Note: This is the type of "super" object, and not the child type of the supertype. + public static SuperObjectValue withType(TypeNode type) { + return builder().setType(type).build(); + } + + private static Builder builder() { + return new AutoValue_SuperObjectValue.Builder(); + } + + @AutoValue.Builder + abstract static class Builder { + abstract Builder setType(TypeNode type); + + abstract SuperObjectValue autoBuild(); + + private SuperObjectValue build() { + SuperObjectValue superObjectValue = autoBuild(); + Preconditions.checkState( + TypeNode.isReferenceType(superObjectValue.type()), + "The \"super\" can only refer to object types"); + return superObjectValue; + } + } +} diff --git a/src/test/java/com/google/api/generator/engine/ast/BUILD.bazel b/src/test/java/com/google/api/generator/engine/ast/BUILD.bazel index 88ed8a8fdd..82bcfe0c6c 100644 --- a/src/test/java/com/google/api/generator/engine/ast/BUILD.bazel +++ b/src/test/java/com/google/api/generator/engine/ast/BUILD.bazel @@ -26,6 +26,7 @@ TESTS = [ "VaporReferenceTest", "MethodInvocationExprTest", "ThisObjectValueTest", + "SuperObjectValueTest", ] filegroup( diff --git a/src/test/java/com/google/api/generator/engine/ast/SuperObjectValueTest.java b/src/test/java/com/google/api/generator/engine/ast/SuperObjectValueTest.java new file mode 100644 index 0000000000..3c7a264ca9 --- /dev/null +++ b/src/test/java/com/google/api/generator/engine/ast/SuperObjectValueTest.java @@ -0,0 +1,52 @@ +// Copyright 2020 Google LLC +// +// 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.api.generator.engine.ast; + +import static org.junit.Assert.assertThrows; + +import org.junit.Test; + +public class SuperObjectValueTest { + + @Test + public void validSuperObjectValue_basic() { + VaporReference ref = + VaporReference.builder() + .setName("Student") + .setPakkage("com.google.example.examples.v1") + .build(); + TypeNode typeNode = TypeNode.withReference(ref); + SuperObjectValue.withType(typeNode); + // No exception thrown, we're good. + } + + @Test + public void invalidSuperObjectValue_nonReferenceType() { + assertThrows( + IllegalStateException.class, + () -> { + SuperObjectValue.withType(TypeNode.DOUBLE); + }); + } + + @Test + public void invalidSuperObjectValue_nullType() { + assertThrows( + IllegalStateException.class, + () -> { + SuperObjectValue.withType(TypeNode.NULL); + }); + } +} diff --git a/src/test/java/com/google/api/generator/engine/writer/ImportWriterVisitorTest.java b/src/test/java/com/google/api/generator/engine/writer/ImportWriterVisitorTest.java index 8456363e71..6cee9eb916 100644 --- a/src/test/java/com/google/api/generator/engine/writer/ImportWriterVisitorTest.java +++ b/src/test/java/com/google/api/generator/engine/writer/ImportWriterVisitorTest.java @@ -33,9 +33,11 @@ import com.google.api.generator.engine.ast.NewObjectExpr; import com.google.api.generator.engine.ast.Reference; import com.google.api.generator.engine.ast.ScopeNode; +import com.google.api.generator.engine.ast.SuperObjectValue; import com.google.api.generator.engine.ast.TernaryExpr; import com.google.api.generator.engine.ast.ThrowExpr; import com.google.api.generator.engine.ast.TypeNode; +import com.google.api.generator.engine.ast.ValueExpr; import com.google.api.generator.engine.ast.VaporReference; import com.google.api.generator.engine.ast.Variable; import com.google.api.generator.engine.ast.VariableExpr; @@ -676,6 +678,25 @@ public void writeMethodDefinitionImports_templatedMixedNamesAndTypes() { "import java.util.Map;\n\n")); } + @Test + public void writeSuperObjectValueImports() { + VaporReference ref = + VaporReference.builder() + .setName("Student") + .setPakkage("com.google.example.examples.v1") + .build(); + TypeNode typeNode = TypeNode.withReference(ref); + SuperObjectValue superObjectValue = SuperObjectValue.withType(typeNode); + MethodInvocationExpr methodExpr = + MethodInvocationExpr.builder() + .setMethodName("getName") + .setExprReferenceExpr(ValueExpr.withValue(superObjectValue)) + .setReturnType(TypeNode.STRING) + .build(); + methodExpr.accept(writerVisitor); + assertEquals(writerVisitor.write(), "import com.google.example.examples.v1.Student;\n\n"); + } + private static TypeNode createType(Class clazz) { return TypeNode.withReference(ConcreteReference.withClazz(clazz)); } diff --git a/src/test/java/com/google/api/generator/engine/writer/JavaWriterVisitorTest.java b/src/test/java/com/google/api/generator/engine/writer/JavaWriterVisitorTest.java index e7e7169645..d380dadcef 100644 --- a/src/test/java/com/google/api/generator/engine/writer/JavaWriterVisitorTest.java +++ b/src/test/java/com/google/api/generator/engine/writer/JavaWriterVisitorTest.java @@ -44,6 +44,7 @@ import com.google.api.generator.engine.ast.ScopeNode; import com.google.api.generator.engine.ast.Statement; import com.google.api.generator.engine.ast.StringObjectValue; +import com.google.api.generator.engine.ast.SuperObjectValue; import com.google.api.generator.engine.ast.TernaryExpr; import com.google.api.generator.engine.ast.ThisObjectValue; import com.google.api.generator.engine.ast.ThrowExpr; @@ -1750,6 +1751,36 @@ public void writeThisObjectValue_accessFieldAndInvokeMethod() { assertThat(writerVisitor.write()).isEqualTo("this.name = this.getName(id)"); } + @Test + public void writeSuperObjectValue_accessFieldAndInvokeMethod() { + VaporReference ref = + VaporReference.builder().setName("Student").setPakkage("com.google.example.v1").build(); + TypeNode classType = TypeNode.withReference(ref); + SuperObjectValue superObjectValue = SuperObjectValue.withType(classType); + ValueExpr superValueExpr = ValueExpr.withValue(superObjectValue); + Variable subVariable = Variable.builder().setName("name").setType(TypeNode.STRING).build(); + VariableExpr superVariableExpr = + VariableExpr.builder() + .setVariable(subVariable) + .setExprReferenceExpr(superValueExpr) + .build(); + + MethodInvocationExpr methodExpr = + MethodInvocationExpr.builder() + .setMethodName("getName") + .setExprReferenceExpr(ValueExpr.withValue(superObjectValue)) + .setReturnType(TypeNode.STRING) + .build(); + AssignmentExpr assignmentExpr = + AssignmentExpr.builder() + .setVariableExpr(superVariableExpr) + .setValueExpr(methodExpr) + .build(); + + assignmentExpr.accept(writerVisitor); + assertThat(writerVisitor.write()).isEqualTo("super.name = super.getName()"); + } + private static String createLines(int numLines) { return new String(new char[numLines]).replace("\0", "%s"); }