diff options
4 files changed, 85 insertions, 4 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/skylarkinterface/processor/SkylarkCallableProcessor.java b/src/main/java/com/google/devtools/build/lib/skylarkinterface/processor/SkylarkCallableProcessor.java index 841bdd1d5a..ef1dc953b7 100644 --- a/src/main/java/com/google/devtools/build/lib/skylarkinterface/processor/SkylarkCallableProcessor.java +++ b/src/main/java/com/google/devtools/build/lib/skylarkinterface/processor/SkylarkCallableProcessor.java @@ -30,6 +30,7 @@ import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; +import javax.lang.model.type.MirroredTypeException; import javax.tools.Diagnostic; /** @@ -48,6 +49,10 @@ import javax.tools.Diagnostic; * The number of method parameters much match the number of annotation-declared parameters * plus the number of interpreter-supplied parameters. * </li> + * <li> + * Each parameter, if explicitly typed, may only use either 'type' or 'allowedTypes', + * not both. + * </li> * </ul> * * <p>These properties can be relied upon at runtime without additional checks. @@ -55,7 +60,6 @@ import javax.tools.Diagnostic; @SupportedAnnotationTypes({"com.google.devtools.build.lib.skylarkinterface.SkylarkCallable"}) @SupportedSourceVersion(SourceVersion.RELEASE_8) public final class SkylarkCallableProcessor extends AbstractProcessor { - private Messager messager; private static final String LOCATION = "com.google.devtools.build.lib.events.Location"; @@ -104,6 +108,26 @@ public final class SkylarkCallableProcessor extends AbstractProcessor { + "empty)", parameter.name())); } + if ((parameter.allowedTypes().length > 0) + && (!"java.lang.Object".equals(paramTypeFieldCanonicalName(parameter)))) { + throw new SkylarkCallableProcessorException( + methodElement, + String.format("Parameter '%s' has both 'type' and 'allowedTypes' specified. Only" + + " one may be specified.", + parameter.name())); + } + } + } + + private String paramTypeFieldCanonicalName(Param param) { + try { + return param.type().toString(); + } catch (MirroredTypeException exception) { + // This is a hack to obtain the actual canonical name of param.type(). Doing this ths + // "correct" way results in far less readable code. + // Since this processor is only for compile-time checks, this isn't efficiency we need + // to worry about. + return exception.getTypeMirror().toString(); } } diff --git a/src/test/java/com/google/devtools/build/lib/skylarkinterface/processor/SkylarkCallableProcessorTest.java b/src/test/java/com/google/devtools/build/lib/skylarkinterface/processor/SkylarkCallableProcessorTest.java index 6459051e0c..7e7291a14e 100644 --- a/src/test/java/com/google/devtools/build/lib/skylarkinterface/processor/SkylarkCallableProcessorTest.java +++ b/src/test/java/com/google/devtools/build/lib/skylarkinterface/processor/SkylarkCallableProcessorTest.java @@ -133,4 +133,15 @@ public final class SkylarkCallableProcessorTest { .withErrorContaining( "Parameter 'a_parameter' has 'None' default value but is not noneable."); } + + @Test + public void testParamTypeConflict() throws Exception { + assertAbout(javaSource()) + .that(getFile("ParamTypeConflict.java")) + .processedWith(new SkylarkCallableProcessor()) + .failsToCompile() + .withErrorContaining( + "Parameter 'a_parameter' has both 'type' and 'allowedTypes' specified." + + " Only one may be specified."); + } } diff --git a/src/test/java/com/google/devtools/build/lib/skylarkinterface/processor/testsources/GoldenCase.java b/src/test/java/com/google/devtools/build/lib/skylarkinterface/processor/testsources/GoldenCase.java index 815ba22bf1..1eb207719f 100644 --- a/src/test/java/com/google/devtools/build/lib/skylarkinterface/processor/testsources/GoldenCase.java +++ b/src/test/java/com/google/devtools/build/lib/skylarkinterface/processor/testsources/GoldenCase.java @@ -16,6 +16,7 @@ package com.google.devtools.build.lib.skylarkinterface.processor.testsources; import com.google.devtools.build.lib.events.Location; import com.google.devtools.build.lib.skylarkinterface.Param; +import com.google.devtools.build.lib.skylarkinterface.ParamType; import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable; import com.google.devtools.build.lib.syntax.Environment; import com.google.devtools.build.lib.syntax.FuncallExpression; @@ -74,10 +75,14 @@ public class GoldenCase { parameters = { @Param(name = "one", type = String.class, named = true), @Param(name = "two", type = Integer.class, named = true), - @Param(name = "three", type = String.class, named = true, defaultValue = "None", - noneable = true), + @Param(name = "three", + allowedTypes = { + @ParamType(type = String.class), + @ParamType(type = Integer.class), + }, + named = true, defaultValue = "None", noneable = true), }) - public String threeArgMethodWithParams(String one, Integer two, String three) { + public String threeArgMethodWithParams(String one, Integer two, Object three) { return "baz"; } diff --git a/src/test/java/com/google/devtools/build/lib/skylarkinterface/processor/testsources/ParamTypeConflict.java b/src/test/java/com/google/devtools/build/lib/skylarkinterface/processor/testsources/ParamTypeConflict.java new file mode 100644 index 0000000000..cda282f9ac --- /dev/null +++ b/src/test/java/com/google/devtools/build/lib/skylarkinterface/processor/testsources/ParamTypeConflict.java @@ -0,0 +1,41 @@ +// Copyright 2018 The Bazel Authors. 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.devtools.build.lib.skylarkinterface.processor.testsources; + +import com.google.devtools.build.lib.skylarkinterface.Param; +import com.google.devtools.build.lib.skylarkinterface.ParamType; +import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable; + +/** + * Test case for a SkylarkCallable method which has a parameter with both type and allowedTypes + * specified. + */ +public class ParamTypeConflict { + + @SkylarkCallable( + name = "param_type_conflict", + doc = "", + parameters = { + @Param(name = "a_parameter", + type = String.class, + named = true, + allowedTypes = { + @ParamType(type = String.class), + }) + }) + public Integer paramTypeConflict() { + return 42; + } +} |