1 package annotator.find;
2 
3 import java.util.List;
4 import java.util.regex.Matcher;
5 import java.util.regex.Pattern;
6 
7 import type.DeclaredType;
8 import type.Type;
9 
10 /**
11  * @author dbro
12  *
13  */
14 public class NewInsertion extends TypedInsertion {
15   private final static Pattern qualifiers = Pattern.compile("(?:\\w++\\.)*+");
16 
17   /**
18    * If true, the type will be qualified with the name of the superclass.
19    */
20   protected boolean qualifyType;
21 
22   /**
23    * Construct a NewInsertion.
24    * <p>
25    * If "new" already exists in the initializer, then pass a
26    * {@link DeclaredType} thats name is the empty String. This will only
27    * insert an annotation on the existing type.
28    * <p>
29    * To insert the annotation along with "new" and the type (for example,
30    * {@code @Anno new Type[] \{...\}}), set the name to the type to insert.
31    * This can be done either before calling this constructor, or by modifying
32    * the return value of {@link #getType()}.
33    *
34    * @param type the type to use when inserting the receiver
35    * @param criteria where to insert the text
36    * @param innerTypeInsertions the inner types to go on this receiver
37    */
NewInsertion(Type type, Criteria criteria, List<Insertion> innerTypeInsertions)38   public NewInsertion(Type type, Criteria criteria,
39       List<Insertion> innerTypeInsertions) {
40     super(type, criteria, innerTypeInsertions);
41     annotationsOnly = false;
42     qualifyType = false;
43   }
44 
45   /** {@inheritDoc} */
46   @Override
getText(boolean comments, boolean abbreviate)47   protected String getText(boolean comments, boolean abbreviate) {
48     if (annotationsOnly || type.getKind() != Type.Kind.ARRAY) {
49       StringBuilder b = new StringBuilder();
50       List<String> annotations = type.getAnnotations();
51       if (annotations.isEmpty()) { return ""; }
52       for (String a : annotations) {
53         b.append(' ').append(a);  // initial space removed below
54       }
55       return new AnnotationInsertion(b.substring(1), getCriteria(),
56           getSeparateLine()).getText(comments, abbreviate);
57     } else {
58       DeclaredType baseType = getBaseType();
59       boolean commentAnnotation = (comments && baseType.getName().isEmpty());
60       String result = typeToString(type, commentAnnotation, abbreviate);
61       if (!baseType.getName().isEmpty()) {
62         // First, temporarily strip off any qualifiers.
63         Matcher matcher = qualifiers.matcher(result);
64         String prefix = "";
65         if (matcher.find() && matcher.start() == 0) {
66           prefix = result.substring(0, matcher.end());
67           result = result.substring(matcher.end());
68         }
69         // If the variable name preceded the array brackets in the
70         // source, extract it from the result.
71         if (qualifyType) {
72           for (DeclaredType t = baseType; t != null; t = t.getInnerType()) {
73             result += t.getName() + ".";
74           }
75         }
76         // Finally, prepend extracted qualifiers.
77         result = prefix + result;
78       }
79       result = "new " + result;
80       if (comments) {
81         result = "/*>>> " + result + " */";
82       }
83       return result;
84     }
85   }
86 
87   /**
88    * If {@code true}, qualify {@code type} with the name of the superclass.
89    * This will only happen if a "new" is inserted.
90    */
setQualifyType(boolean qualifyType)91   public void setQualifyType(boolean qualifyType) {
92     this.qualifyType = qualifyType;
93   }
94 
95   /** {@inheritDoc} */
96   @Override
addLeadingSpace(boolean gotSeparateLine, int pos, char precedingChar)97   protected boolean addLeadingSpace(boolean gotSeparateLine, int pos,
98       char precedingChar) {
99     if ((precedingChar == '.' || precedingChar == '(')
100         && getBaseType().getName().isEmpty()) {
101       // If only the annotation is being inserted then don't insert a
102       // space if it's immediately after a '.' or '('
103       return false;
104     }
105     return super.addLeadingSpace(gotSeparateLine, pos, precedingChar);
106   }
107 
108   /** {@inheritDoc} */
109   @Override
addTrailingSpace(boolean gotSeparateLine)110   protected boolean addTrailingSpace(boolean gotSeparateLine) {
111     return true;
112   }
113 
114   /** {@inheritDoc} */
115   @Override
getKind()116   public Kind getKind() {
117     return Kind.NEW;
118   }
119 }
120