summaryrefslogtreecommitdiffstats
path: root/jack/src/com/android/jack/transformations/typedef/TypeDefRemover.java
blob: d646606a365f6a3a7034db73f048848eb081fa89 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/*
 * Copyright (C) 2012 The Android Open Source Project
 *
 * 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.android.jack.transformations.typedef;

import com.android.jack.Jack;
import com.android.jack.ir.ast.JDefinedAnnotationType;
import com.android.jack.ir.ast.JDefinedClassOrInterface;
import com.android.jack.ir.ast.JMethod;
import com.android.jack.ir.ast.JRetentionPolicy;
import com.android.jack.reporting.Reportable;
import com.android.jack.reporting.Reporter.Severity;
import com.android.jack.transformations.TypeRemover;
import com.android.jack.transformations.typedef.TypeDefRemover.RemoveTypeDef;
import com.android.sched.item.Description;
import com.android.sched.item.Feature;
import com.android.sched.item.Synchronized;
import com.android.sched.schedulable.RunnableSchedulable;
import com.android.sched.schedulable.Support;
import com.android.sched.util.config.HasKeyId;
import com.android.sched.util.config.id.BooleanPropertyId;

import javax.annotation.Nonnull;

/**
 * A {@link RunnableSchedulable} removing @StringDef, @IntDef and all annotations
 * annotated with them.
 */
@Description("Removes @StringDef, @IntDef and all annotations annotated with them")
@Synchronized
@Support(RemoveTypeDef.class)
@HasKeyId
public class TypeDefRemover extends TypeRemover {

  @Nonnull
  public static final BooleanPropertyId REMOVE_TYPEDEF = BooleanPropertyId.create(
      "jack.android.remove-typedef",
      "Removes @StringDef, @IntDef and all annotations annotated with them")
      .addDefaultValue(false);

  /**
   * A {@link Feature} allowing to remove @StringDef, @IntDef and all annotations annotated with
   * them.
   */
  @Description("Removes @StringDef, @IntDef and all annotations annotated with them")
  public static class RemoveTypeDef implements Feature {
  }

  private static class InvalidRetentionForTypeDef implements Reportable {

    @Nonnull
    private final JDefinedAnnotationType typeDef;

    public InvalidRetentionForTypeDef(@Nonnull JDefinedAnnotationType typeDef) {
      this.typeDef = typeDef;
    }

    @Override
    @Nonnull
    public String getMessage() {
      return "Annotation @" + Jack.getUserFriendlyFormatter().getName(typeDef)
          + "should be annotated with @Retention(RetentionPolicy.SOURCE)";
    }

    @Override
    @Nonnull
    public ProblemLevel getDefaultProblemLevel() {
      return ProblemLevel.WARNING;
    }
  }

  private static class InvalidTypeDefTarget implements Reportable {

    @Nonnull
    private final JDefinedClassOrInterface annotated;

    public InvalidTypeDefTarget(@Nonnull JDefinedClassOrInterface annotated) {
      this.annotated = annotated;
    }

    @Override
    @Nonnull
    public String getMessage() {
      return "Type " + Jack.getUserFriendlyFormatter().getName(annotated)
          + " should not be annotated with @IntDef or @StringDef,"
          + " only annotations are valid targets";
    }

    @Override
    @Nonnull
    public ProblemLevel getDefaultProblemLevel() {
      return ProblemLevel.WARNING;
    }
  }

  @Nonnull
  private final JDefinedAnnotationType stringDef =
    Jack.getSession().getLookup().getAnnotationType("Landroid/annotation/StringDef;");

  @Nonnull
  private final JDefinedAnnotationType intDef =
    Jack.getSession().getLookup().getAnnotationType("Landroid/annotation/IntDef;");

  @Override
  protected boolean mustBeRemoved(@Nonnull JDefinedClassOrInterface type) {
    if (type instanceof JDefinedAnnotationType) {
      if ((!type.getAnnotations(stringDef).isEmpty()) || !type.getAnnotations(intDef).isEmpty()) {
        JDefinedAnnotationType typeDef = (JDefinedAnnotationType) type;
        if (typeDef.getRetentionPolicy() != JRetentionPolicy.SOURCE) {
          type.getSession().getReporter().report(Severity.NON_FATAL,
              new InvalidRetentionForTypeDef(typeDef));
        }
        return true;
      }
    } else if ((!type.getAnnotations(stringDef).isEmpty())
        || !type.getAnnotations(intDef).isEmpty()) {
      Jack.getSession().getReporter().report(Severity.NON_FATAL,
          new InvalidTypeDefTarget(type));
    }
    return false;
  }

  @Override
  protected boolean isPlannedForRemoval(@Nonnull JMethod method) {
    return mustBeRemoved(method.getEnclosingType());
  }
}