2016-04-11 3 views
6

Например, я хотел создать аннотацию @Out для целевых параметров. Затем я каким-то образом воспользуюсь компилятором, чтобы проверить, установлено ли значение параметра до возвращения функции. Это возможно?Могу ли я использовать аннотации Java для определения времени проверки компиляции?

Также думал о @Immutable аннотации, которая не позволяла бы любому методу, который не был бы аннотирован с помощью @Const, для вызова или доступа к любым открытым полям. (Время компиляции и, вероятно, во время выполнения?)

До сих пор у меня есть это:

//I'm assuming Class retention is a subset of Runtime retention 
@Retention(RetentionPolicy.RUNTIME) 
@Target(ElementType.PARAMETER) 
public @interface Out 
{ 
    //no idea what to go in here. 
} 

это другая аннотаций. опять же, у меня нет полного определения для него:

@Retention(RetentionPolicy.RUNTIME) 
@Target(ElementType.TYPE) 
public @interface Immutable 
{ 

} 

Я думаю, что я могу начать разработать стратегию реализации, что во время выполнения с помощью отражения, но я хотел бы указать компилятор или препроцессор, чтобы проверить, что материал для я вместо этого, поэтому мои аннотации будут иметь нулевые накладные расходы.

Это одна из тех вещей, которые, по вашему мнению, «если бы это могло быть сделано, это уже было бы там, и если да, то где я могу ее схватить».

Редактировать: После того, как в дальнейшем думал о @Const и @Immutable и после запоминания ява передает указатели на объекты по значению, я расширил определение @Const, избавившись от @Immutable, и изменил определение @Out, следующим ниже:

/** 
* When Applied to a method, ensures the method doesn't change in any 
* way the state of the object used to invoke it, i.e., all the fields 
* of the object must remain the same, and no field may be returned, 
* unless the field itself is marked as {@code @Const}. A method 
* annotated with {@code @Const} can only invoke other {@code @Const} 
* methods of its class, can only use the class's fields to invoke 
* {@code @Const} methods of the fields classes and can only pass fields 
* as parameters to methods that annotate that formal parameter as 
* {@code @Const}. 
* 
* When applied to a formal parameter, ensures the method will not 
* modify the value referenced by the formal parameter. A formal 
* parameter annotated as {@code @Const} will not be aliased inside the 
* body of the method. The method is not allowed to invoke another 
* method and pass the annotated parameter, save if the other method 
* also annotates the formal parameter as {@code @Const}. The method is 
* not allowed to use the parameter to invoke any of its type's methods, 
* unless the method being invoked is also annotated as {@code @Const} 
* 
* When applied to a field, ensures the field cannot be aliased and that 
* no code can alter the state of that field, either from inside the 
* class that owns the field or from outside it. Any constructor in any 
* derived class is allowed to set the value of the field and invoke any 
* methods using it. As for methods, only those annotated as 
* {@code @Const} may be invoked using the field. The field may only be 
* passed as a parameter to a method if the method annotates the 
* corresponding formal parameter as {@code @Const} 
* 
* When applied to a local variable, ensures neither the block where the 
* variable is declared or any nested block will alter the value of that 
* local variable. The local variable may be defined only once, at any 
* point where it is in scope. Only methods annotated as 
* {@code @Const} may be invoked using this variable, and the variable 
* may only be passed as a parameter to another method if said method 
* annotates its corresponding formal parameter as {@code @Const} 
* 
*/ 
@Retention(RetentionPolicy.SOURCE) 
@Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, 
ElementType.LOCAL_VARIABLE}) 
@Inherited 
public @interface Const 
{ 

} 

теперь @Out:

/** 
* The formal parameter annotated with {@code @Out} must be undefined in 
* the scope of the caller, and it's the responsibility of the method to 
* define it. If allowNull is true, the parameter can be explicitly set 
* to null in the body of the method. 
*/ 
@Retention(RetentionPolicy.SOURCE) 
@Target(ElementType.PARAMETER) 
public @interface Out 
{ 
    boolean allowNull() default false; 
} 

Редактировать: Я пытаюсь реализовать это как плагин eclipse, но я полностью потерял чтение руководства. Я написал плагин с базовой логикой для доступа к методам и полям AST и посещениям. Затем я сделал кучу фиктивных аннотаций, которые должен обнаружить мой плагин, затем я пытаюсь распечатать результаты, но я даже не уверен, чего ожидать. Мой плагин - это плагин «Инкрементальная сборка». Вот код для этого: если кто-то может взглянуть и просто объяснит мне кое-что. Я полностью потерял этот API.

https://github.com/Starless2001/Plugin-for-Eclipse

+2

Серьезно, я думаю, что для того, чтобы делать то, что вы хотите, вам нужен компилятор, который каким-то образом поддерживает настраиваемые пользователем плагины. И я не знаю никого из них. Это звучит очень сложно, с точки зрения автора-писателя. – ajb

+0

@ajb, что неутешительно. аннотации должны работать как языковые расширения. – FinnTheHuman

+0

Я мог бы создать что-то вроде компилятора. предварительный компилятор, pehaps? – FinnTheHuman

ответ

6

Javac компилятор поддерживает определяемые пользователем модули, называемые аннотаций процессоры, которые выполняют именно то, что вы хотите. Вы можете рассматривать аннотации как языковые расширения.

Определение public @interface Immutable { ... } определяет синтаксис: аннотация @Immutable, которую вы можете записать в своей программе. Обработчик аннотации (плагин компилятора) определяет семантику: он применяет семантические правила и предупреждает о компиляторе, когда ваша программа нарушает правила.

Одним из элементов, упрощающих запись таких обработчиков аннотаций, является Checker Framework и содержит определения аннотаций, например @NonNull и @Immutable. Вот два учебника о том, как использовать Checker Framework для проверки кода: tutorial 1, tutorial 2.

В каждой декларации вызывается обычная обработка аннотаций Java, такая как классы, поля, методы и параметры метода, а обычная Java дает обработчику аннотации никакого доступа к полному AST. Вы можете подумать о Checker Framework как библиотеке, которая расширяет возможности обработки аннотаций Java. Это дает вам доступ к полному AST каждого класса и позволяет вам определять правила для каждого оператора в вашей программе. Таким образом, ваш обработчик аннотации может выдавать предупреждения, когда оператор вызывает метод @Const объекта @Immutable.

Ваш обработчик аннотации должен быть модульным, работая по одному классу за раз. Обработчик аннотации имеет доступ к AST текущего класса, а также к подписям, включая аннотации, всех классов, которые он использует. Обработка аннотаций дает вам эту информацию (но не весь АСТ всего проекта сразу).

+0

Я реализую его таким образом. Спасибо за помощь. Мне не нравится checker framework, потому что он медленный и неполный. вам нужно несколько «шашек», чтобы определить просто неизменность. Как только он будет готов, я опубликую, кто знает, кто-то может найти его полезным. – FinnTheHuman

+0

Звучит здорово. Пожалуйста, поделитесь своими результатами. – mernst