/* * Copyright 2014 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.errorprone.refaster.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Annotation to indicate a placeholder method. * * <p>A placeholder method is an abstract method in a Refaster template class which can represent * an arbitrary expression (if the return type is nonvoid), or zero or more statements * (if the return type is void), in terms of its arguments. For example, * * <pre><code> * abstract class ComputeIfAbsent<K, V> { * {@literal @}Placeholder abstract V computeValue(K key); * * {@literal @}BeforeTemplate void getOrCompute(Map<K, V> map, K key) { * V value = map.get(key); * if (value == null) { * map.put(key, value = computeValue(key)); * } * } * * {@literal @}AfterTemplate void computeIfAbsent(Map<K, V> map, K key) { * V value = map.computeIfAbsent(key, (K k) -> computeValue(k)); * } * } * </code></pre> * * <p>Here, {@code computeValue} represents an arbitrary expression in terms of {@code key}, * and the {@code @AfterTemplate} rewrites that same expression in terms of the parameter of a * lambda expression. * * <p>For a multi-line example, consider * * <pre><code> * abstract class TryWithResources<T extends AutoCloseable> { * {@literal @}Placeholder abstract T open(); * {@literal @}Placeholder void process(T resource); * * {@literal @}BeforeTemplate void tryFinallyClose() { * T resource = open(); * try { * process(resource); * } finally { * resource.close(); * } * } * * {@literal @}AfterTemplate void tryWithResource() { * try (T resource = open()) { * process(resource); * } * } * } * </code></pre> * * <p>Here, {@code process} is any block, though it must refer to {@code resource} in some way; * it is not permitted to reassign the contents of {@code resource}. * * <p>Placeholder methods are not permitted to refer to any local variables or parameters of the * {@code @BeforeTemplate} that are not passed to them as arguments, and must currently contain * references to all arguments that <em>are</em> passed to them. * * @author lowasser@google.com (Louis Wasserman) */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.SOURCE) public @interface Placeholder { // TODO(lowasser): consider putting forbiddenKinds here as an annotation parameter /** * Identifies whether the placeholder is allowed to match an expression which simply returns one * of the placeholder arguments unchanged. */ boolean allowsIdentity() default false; }