1 /*******************************************************************************
2  * Copyright (c) 2019 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *     Sebastian Davids: sdavids@gmx.de - see bug 25376
14  *     Lukas Hanke <hanke@yatta.de> - [templates][content assist] Content assist for 'for' loop should suggest member variables - https://bugs.eclipse.org/117215
15  *     Lars Vogel <Lars.Vogel@vogella.com> - Bug 488432
16  *     Microsoft Corporation - moved template related code to jdt.core.manipulation - https://bugs.eclipse.org/549989
17  *******************************************************************************/
18 package org.eclipse.jdt.internal.corext.template.java;
19 
20 import org.eclipse.jface.text.IDocument;
21 import org.eclipse.jface.text.Position;
22 import org.eclipse.jface.text.templates.DocumentTemplateContext;
23 import org.eclipse.jface.text.templates.GlobalTemplateVariables;
24 import org.eclipse.jface.text.templates.TemplateContext;
25 import org.eclipse.jface.text.templates.TemplateVariable;
26 import org.eclipse.jface.text.templates.TemplateVariableResolver;
27 
28 import org.eclipse.jdt.core.ICompilationUnit;
29 import org.eclipse.jdt.core.IJavaProject;
30 
31 import org.eclipse.jdt.internal.core.manipulation.StubUtility;
32 import org.eclipse.jdt.internal.corext.template.java.CompilationUnitCompletion.Variable;
33 
34 import org.eclipse.jdt.internal.ui.text.template.contentassist.MultiVariable;
35 
36 
37 /**
38  * An abstract context type for templates inside Java code.
39  *
40  * @since 3.4
41  */
42 public abstract class AbstractJavaContextTypeCore extends CompilationUnitContextType {
43 
44 
45 	protected static abstract class AbstractIterable extends TemplateVariableResolver {
AbstractIterable(String type, String description)46 		public AbstractIterable(String type, String description) {
47 			super(type, description);
48 		}
49 
50 		@Override
resolveAll(TemplateContext context)51 		protected String[] resolveAll(TemplateContext context) {
52 	        IJavaContext jc= (IJavaContext) context;
53 	        Variable[] iterables= getVariables(jc);
54 	        String[] names= new String[iterables.length];
55 	        for (int i= 0; i < iterables.length; i++)
56 				names[i]= iterables[i].getName();
57 	        if (names.length > 0)
58 	        	jc.markAsUsed(names[0]);
59 			return names;
60 	    }
61 
getVariables(IJavaContext jc)62 		abstract protected Variable[] getVariables(IJavaContext jc);
63 
64 		/*
65 		 * @see org.eclipse.jface.text.templates.TemplateVariableResolver#resolve(org.eclipse.jface.text.templates.TemplateVariable, org.eclipse.jface.text.templates.TemplateContext)
66 		 */
67 		@Override
resolve(TemplateVariable variable, TemplateContext context)68 		public void resolve(TemplateVariable variable, TemplateContext context) {
69 			if (variable instanceof MultiVariable) {
70 				IJavaContext jc= (IJavaContext) context;
71 				JavaVariable jv= (JavaVariable) variable;
72 		        Variable[] iterables= getVariables(jc);
73 				if (iterables.length > 0) {
74 					jv.setChoices(iterables);
75 					jc.markAsUsed(iterables[0].getName());
76 
77 					if (iterables.length > 1)
78 						variable.setUnambiguous(false);
79 					else
80 						variable.setUnambiguous(isUnambiguous(context));
81 
82 					return;
83 				}
84 			}
85 
86 			super.resolve(variable, context);
87 		}
88 	}
89 
90 	protected static class Array extends AbstractIterable {
Array()91 		public Array() {
92 			super("array", JavaTemplateMessages.JavaContextType_variable_description_array);  //$NON-NLS-1$
93 		}
94 
95 		@Override
getVariables(IJavaContext jc)96 		protected Variable[] getVariables(IJavaContext jc) {
97 			return jc.getArrays();
98 		}
99 	}
100 
101 	protected static class Iterable extends AbstractIterable {
Iterable()102 		public Iterable() {
103 		    super("iterable", JavaTemplateMessages.JavaContextType_variable_description_iterable);  //$NON-NLS-1$
104 		}
105 
106 		@Override
getVariables(IJavaContext jc)107 		protected Variable[] getVariables(IJavaContext jc) {
108 			return jc.getIterables();
109 		}
110 	}
111 
112 	protected static abstract class AbstractIterableType extends TemplateVariableResolver {
113 		private String fMasterName;
114 
AbstractIterableType(String type, String desc, String master)115 	    public AbstractIterableType(String type, String desc, String master) {
116 	     	super(type, desc);
117 	     	fMasterName= master;
118 	    }
119 	    @Override
resolveAll(TemplateContext context)120 		protected String[] resolveAll(TemplateContext context) {
121 	        IJavaContext jc= (IJavaContext) context;
122 	        Variable[] iterables= getVariablesInContextScope(jc);
123 	        String[] types= new String[iterables.length];
124 	        for (int i= 0; i < iterables.length; i++)
125 	        	types[i]= iterables[i].getMemberTypeNames()[0];
126 			return types;
127 	    }
128 
getVariablesInContextScope(IJavaContext jc)129 		abstract protected Variable[] getVariablesInContextScope(IJavaContext jc);
130 
131 		/*
132 		 * @see org.eclipse.jface.text.templates.TemplateVariableResolver#resolve(org.eclipse.jface.text.templates.TemplateVariable, org.eclipse.jface.text.templates.TemplateContext)
133 		 */
134 		@Override
resolve(TemplateVariable variable, TemplateContext context)135 		public void resolve(TemplateVariable variable, TemplateContext context) {
136 			if (variable instanceof MultiVariable) {
137 				IJavaContext jc= (IJavaContext) context;
138 				MultiVariable mv= (MultiVariable) variable;
139 
140 				Variable[] iterables= getVariablesInContextScope(jc);
141 				if (iterables.length > 0) {
142 
143 					for (Variable iterable : iterables)
144 						mv.setChoices(iterable, iterable.getMemberTypeNames());
145 
146 					TemplateVariable master= jc.getTemplateVariable(fMasterName);
147 					if (master instanceof MultiVariable) {
148 						final MultiVariable masterMv= (MultiVariable) master;
149 						jc.addDependency(masterMv, mv);
150 						mv.setKey(masterMv.getCurrentChoice());
151 					}
152 
153 					if (iterables.length > 1 || iterables.length == 1 && mv.getChoices().length > 1)
154 						variable.setUnambiguous(false);
155 					else
156 						variable.setUnambiguous(isUnambiguous(context));
157 
158 					return;
159 				}
160 
161 			}
162 
163 			super.resolve(variable, context);
164 		}
165 	}
166 
167 	protected static class ArrayType extends AbstractIterableType {
ArrayType()168 		public ArrayType() {
169 			super("array_type", JavaTemplateMessages.JavaContextType_variable_description_array_type, "array");  //$NON-NLS-1$ //$NON-NLS-2$
170 		}
171 		@Override
getVariablesInContextScope(IJavaContext jc)172 		protected Variable[] getVariablesInContextScope(IJavaContext jc) {
173 			return jc.getArrays();
174 		}
175 	}
176 
177 	protected static class IterableType extends AbstractIterableType {
IterableType()178 		public IterableType() {
179 	     	super("iterable_type", JavaTemplateMessages.JavaContextType_variable_description_iterable_type, "iterable");  //$NON-NLS-1$ //$NON-NLS-2$
180 		}
181 		@Override
getVariablesInContextScope(IJavaContext jc)182 		protected Variable[] getVariablesInContextScope(IJavaContext jc) {
183 			return jc.getIterables();
184 		}
185 	}
186 
187 	protected static abstract class AbstractIterableElement extends TemplateVariableResolver {
188 		private String fMasterName;
189 
AbstractIterableElement(String type, String desc, String master)190 	    public AbstractIterableElement(String type, String desc, String master) {
191 	     	super(type, desc);
192 	     	fMasterName= master;
193 	    }
194 
195 	    @Override
resolveAll(TemplateContext context)196 		protected String[] resolveAll(TemplateContext context) {
197 	        IJavaContext jc= (IJavaContext) context;
198 	        Variable[] iterables= getLocalVariables(jc);
199 	        String[] elements= new String[iterables.length];
200 	        for (int i= 0; i < iterables.length; i++) {
201 	        	elements[i]= jc.suggestVariableNames(iterables[i].getMemberTypeNames()[0])[0];
202 	        	if (i == 0)
203 	        		jc.markAsUsed(elements[0]);
204 	        }
205 
206 	        return elements;
207 	    }
208 
getLocalVariables(IJavaContext jc)209 		abstract protected Variable[] getLocalVariables(IJavaContext jc);
210 
211 		/*
212 		 * @see org.eclipse.jface.text.templates.TemplateVariableResolver#resolve(org.eclipse.jface.text.templates.TemplateVariable, org.eclipse.jface.text.templates.TemplateContext)
213 		 */
214 		@Override
resolve(TemplateVariable variable, TemplateContext context)215 		public void resolve(TemplateVariable variable, TemplateContext context) {
216 			if (variable instanceof MultiVariable) {
217 				IJavaContext jc= (IJavaContext) context;
218 				MultiVariable mv= (MultiVariable) variable;
219 
220 		        Variable[] iterables= getLocalVariables(jc);
221 				if (iterables.length > 0) {
222 					for (Variable iterable : iterables) {
223 						String[] elements= jc.suggestVariableNames(iterable.getMemberTypeNames()[0]);
224 						mv.setChoices(iterable, elements);
225 					}
226 
227 
228 					TemplateVariable master= jc.getTemplateVariable(fMasterName);
229 					if (master instanceof MultiVariable) {
230 						final MultiVariable masterMv= (MultiVariable) master;
231 						jc.addDependency(masterMv, mv);
232 						mv.setKey(masterMv.getCurrentChoice());
233 					}
234 					jc.markAsUsed(mv.getDefaultValue());
235 
236 					if (iterables.length > 1 || iterables.length == 1 && mv.getChoices().length > 1)
237 						variable.setUnambiguous(false);
238 					else
239 						variable.setUnambiguous(isUnambiguous(context));
240 
241 					return;
242 				}
243 
244 			}
245 			super.resolve(variable, context);
246 		}
247 	}
248 
249 	protected static class ArrayElement extends AbstractIterableElement {
ArrayElement()250 		public ArrayElement() {
251 			super("array_element", JavaTemplateMessages.JavaContextType_variable_description_array_element, "array");	 //$NON-NLS-1$ //$NON-NLS-2$
252 		}
253 		@Override
getLocalVariables(IJavaContext jc)254 		protected Variable[] getLocalVariables(IJavaContext jc) {
255 			return jc.getArrays();
256 		}
257 	}
258 
259 	protected static class IterableElement extends AbstractIterableElement {
IterableElement()260 		public IterableElement() {
261 	     	super("iterable_element", JavaTemplateMessages.JavaContextType_variable_description_iterable_element, "iterable");	 //$NON-NLS-1$ //$NON-NLS-2$
262 		}
263 		@Override
getLocalVariables(IJavaContext jc)264 		protected Variable[] getLocalVariables(IJavaContext jc) {
265 			return jc.getIterables();
266 		}
267 	}
268 
269 	protected static class Index extends NameResolver {
Index()270 	    public Index() {
271 	    	super("int"); //$NON-NLS-1$
272 	     	setType("index"); //$NON-NLS-1$
273 	     	setDescription(JavaTemplateMessages.JavaContextType_variable_description_index);
274 	    }
275 	}
276 
277 	protected static class Collection extends VarResolver {
Collection()278 	    public Collection() {
279 	    	super("java.util.Collection"); //$NON-NLS-1$
280 	    	setType("collection"); //$NON-NLS-1$
281 	    	setDescription(JavaTemplateMessages.JavaContextType_variable_description_collection);
282 		}
283 	}
284 
285 	protected static class Iterator extends NameResolver {
Iterator()286 	    public Iterator() {
287 	    	super("java.util.Iterator"); //$NON-NLS-1$
288 	     	setType("iterator"); //$NON-NLS-1$
289 	     	setDescription(JavaTemplateMessages.JavaContextType_variable_description_iterator);
290 		}
291 	}
292 
293 	protected static class Todo extends TemplateVariableResolver {
294 
Todo()295 		public Todo() {
296 			super("todo", JavaTemplateMessages.JavaContextType_variable_description_todo);  //$NON-NLS-1$
297 		}
298 		@Override
resolve(TemplateContext context)299 		protected String resolve(TemplateContext context) {
300 			IJavaContext javaContext= (IJavaContext) context;
301 			ICompilationUnit compilationUnit= javaContext.getCompilationUnit();
302 			if (compilationUnit == null)
303 				return "XXX"; //$NON-NLS-1$
304 
305 			IJavaProject javaProject= compilationUnit.getJavaProject();
306 			String todoTaskTag= StubUtility.getTodoTaskTag(javaProject);
307 			if (todoTaskTag == null)
308 				return "XXX"; //$NON-NLS-1$
309 
310 			return todoTaskTag;
311 		}
312 	}
313 /*
314 	protected static class Arguments extends SimpleVariableResolver {
315 	    public Arguments() {
316 	     	super("arguments", TemplateMessages.getString("Javavariable.description.arguments"), "");
317 	    }
318 	}
319 */
320 
321 	/**
322 	 * Initializes the context type resolvers.
323 	 * <p>
324 	 * <strong>Note:</strong> Only call this method if this
325 	 * context type doesn't inherit from another context type
326 	 * which already has these resolvers.</p>
327 	 *
328 	 * @since 3.4
329 	 */
initializeContextTypeResolvers()330 	public void initializeContextTypeResolvers() {
331 
332 		// global
333 		addResolver(new GlobalTemplateVariables.Cursor());
334 		addResolver(new GlobalTemplateVariables.WordSelection());
335 		addResolver(new GlobalTemplateVariables.Selection(GlobalTemplateVariables.LineSelection.NAME, JavaTemplateMessages.CompilationUnitContextType_variable_description_line_selection));
336 		addResolver(new GlobalTemplateVariables.Dollar());
337 		addResolver(new GlobalTemplateVariables.Date());
338 		addResolver(new GlobalTemplateVariables.Year());
339 		addResolver(new GlobalTemplateVariables.Time());
340 		addResolver(new GlobalTemplateVariables.User());
341 
342 		// compilation unit
343 		addResolver(new File());
344 		addResolver(new PrimaryTypeName());
345 		addResolver(new ReturnType());
346 		addResolver(new Method());
347 		addResolver(new Type());
348 		addResolver(new Package());
349 		addResolver(new Project());
350 		addResolver(new Arguments());
351 
352 		// java
353 		addResolver(new Array());
354 		addResolver(new ArrayType());
355 		addResolver(new ArrayElement());
356 		addResolver(new Index());
357 		addResolver(new Iterator());
358 		addResolver(new Collection());
359 		addResolver(new Iterable());
360 		addResolver(new IterableType());
361 		addResolver(new IterableElement());
362 		addResolver(new Todo());
363 	}
364 
365 
366 	/*
367 	 * @see org.eclipse.jdt.internal.corext.template.java.CompilationUnitContextType#createContext(org.eclipse.jface.text.IDocument, int, int, org.eclipse.jdt.core.ICompilationUnit)
368 	 */
369 	@Override
createContext(IDocument document, int offset, int length, ICompilationUnit compilationUnit)370 	public DocumentTemplateContext createContext(IDocument document, int offset, int length, ICompilationUnit compilationUnit) {
371 		JavaContextCore javaContext= new JavaContextCore(this, document, offset, length, compilationUnit);
372 		initializeContext(javaContext);
373 		return javaContext;
374 	}
375 
376 	/*
377 	 * @see org.eclipse.jdt.internal.corext.template.java.CompilationUnitContextType#createContext(org.eclipse.jface.text.IDocument, org.eclipse.jface.text.Position, org.eclipse.jdt.core.ICompilationUnit)
378 	 */
379 	@Override
createContext(IDocument document, Position completionPosition, ICompilationUnit compilationUnit)380 	public DocumentTemplateContext createContext(IDocument document, Position completionPosition, ICompilationUnit compilationUnit) {
381 		JavaContextCore javaContext= new JavaContextCore(this, document, completionPosition, compilationUnit);
382 		initializeContext(javaContext);
383 		return javaContext;
384 	}
385 
386 	/**
387 	 * Hook to initialize the context
388 	 *
389 	 * @param context the context
390 	 */
initializeContext(IJavaContext context)391 	protected void initializeContext(IJavaContext context) {
392 	}
393 
394 }
395