1 package annotator.find;
2 
3 import java.util.List;
4 
5 import type.DeclaredType;
6 
7 /**
8  * An insertion for a method receiver. This supports inserting an
9  * annotation on an existing receiver and creating a new (annotated)
10  * receiver if none are present.
11  */
12 public class ReceiverInsertion extends TypedInsertion {
13     /**
14      * If true a comma will be added at the end of the insertion (only if also
15      * inserting the receiver).
16      */
17     private boolean addComma;
18 
19     /**
20      * If true, {@code this} will be qualified with the name of the
21      * superclass.
22      */
23     private boolean qualifyThis;
24 
25     /**
26      * Construct a ReceiverInsertion.
27      * <p>
28      * If the receiver parameter already exists in the method declaration, then
29      * pass a DeclaredType thats name is the empty String. This will only insert
30      * an annotation on the existing receiver.
31      * <p>
32      * To insert the annotation and the receiver (for example,
33      * {@code @Anno Type this}) the name should be set to the type to insert.
34      * This can either be done before calling this constructor, or by modifying
35      * the return value of {@link #getType()}.
36      * <p>
37      * A comma will not be added to the end of the receiver. In the case that
38      * there is a parameter following the inserted receiver pass {@code true} to
39      * {@link #setAddComma(boolean)} to add a comma to the end of the receiver.
40      *
41      * @param type the type to use when inserting the receiver
42      * @param criteria where to insert the text
43      * @param innerTypeInsertions the inner types to go on this receiver
44      */
ReceiverInsertion(DeclaredType type, Criteria criteria, List<Insertion> innerTypeInsertions)45     public ReceiverInsertion(DeclaredType type, Criteria criteria, List<Insertion> innerTypeInsertions) {
46         super(type, criteria, innerTypeInsertions);
47         addComma = false;
48         qualifyThis = false;
49     }
50 
51     /**
52      * If {@code true} a comma will be added at the end of the receiver.
53      * This will only happen if a receiver is inserted (see
54      * {@link #ReceiverInsertion(DeclaredType, Criteria, List)} for a description of
55      * when a receiver is inserted). This is useful if the method already has
56      * one or more parameters.
57      */
setAddComma(boolean addComma)58     public void setAddComma(boolean addComma) {
59         this.addComma = addComma;
60     }
61 
62     /**
63      * If {@code true}, qualify {@code this} with the name of the superclass.
64      * This will only happen if a receiver is inserted (see
65      * {@link #ReceiverInsertion(DeclaredType, Criteria, List)}
66      * for a description of when a receiver is inserted). This is useful
67      * for inner class constructors.
68      */
setQualifyType(boolean qualifyThis)69     public void setQualifyType(boolean qualifyThis) {
70         this.qualifyThis = qualifyThis;
71     }
72 
73     /** {@inheritDoc} */
74     @Override
getText(boolean comments, boolean abbreviate)75     protected String getText(boolean comments, boolean abbreviate) {
76       if (annotationsOnly) {
77         StringBuilder b = new StringBuilder();
78         List<String> annotations = type.getAnnotations();
79         if (annotations.isEmpty()) { return ""; }
80         for (String a : annotations) {
81             b.append(a);
82             b.append(' ');
83         }
84         return new AnnotationInsertion(b.toString(), getCriteria(),
85                 getSeparateLine()).getText(comments, abbreviate);
86       } else {
87         DeclaredType baseType = getBaseType();
88         boolean commentAnnotation = (comments && baseType.getName().isEmpty());
89         String result = typeToString(type, commentAnnotation, abbreviate);
90         if (!baseType.getName().isEmpty()) {
91             result += " ";
92             if (qualifyThis) {
93                 for (DeclaredType t = baseType; t != null;
94                         t = t.getInnerType()) {
95                     result += t.getName() + ".";
96                 }
97             }
98             result += "this";
99             if (addComma) {
100                 result += ",";
101             }
102             if (comments) {
103                 result = "/*>>> " + result + " */";
104             }
105         }
106         return result;
107       }
108     }
109 
110     /** {@inheritDoc} */
111     @Override
addLeadingSpace(boolean gotSeparateLine, int pos, char precedingChar)112     protected boolean addLeadingSpace(boolean gotSeparateLine, int pos,
113             char precedingChar) {
114         if (precedingChar == '.' && getBaseType().getName().isEmpty()) {
115             // If only the annotation is being inserted then don't insert a
116             // space if it's immediately after a '.'
117             return false;
118         }
119         return super.addLeadingSpace(gotSeparateLine, pos, precedingChar);
120     }
121 
122     /** {@inheritDoc} */
123     @Override
addTrailingSpace(boolean gotSeparateLine)124     protected boolean addTrailingSpace(boolean gotSeparateLine) {
125         // If the type is not already in the source and the receiver is the only
126         // parameter, don't add a trailing space.
127         if (!getBaseType().getName().isEmpty() && !addComma) {
128             return false;
129         }
130         return super.addTrailingSpace(gotSeparateLine);
131     }
132 
133     /** {@inheritDoc} */
134     @Override
getKind()135     public Kind getKind() {
136         return Kind.RECEIVER;
137     }
138 }
139