1 /*******************************************************************************
2  * Copyright (c) 2000, 2017 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  *     Alex Smirnoff (alexsmr@sympatico.ca) - part of the changes to support Java-like extension
14  *                                                            (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=71460)
15  *******************************************************************************/
16 package org.eclipse.jdt.internal.core;
17 
18 import java.io.IOException;
19 import java.util.*;
20 
21 import org.eclipse.core.resources.*;
22 import org.eclipse.core.runtime.*;
23 import org.eclipse.jdt.core.*;
24 import org.eclipse.jdt.core.compiler.*;
25 import org.eclipse.jdt.core.dom.AST;
26 import org.eclipse.jdt.internal.compiler.IProblemFactory;
27 import org.eclipse.jdt.internal.compiler.SourceElementParser;
28 import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
29 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
30 import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
31 import org.eclipse.jdt.internal.compiler.problem.AbortCompilationUnit;
32 import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
33 import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
34 import org.eclipse.jdt.internal.core.util.MementoTokenizer;
35 import org.eclipse.jdt.internal.core.util.Messages;
36 import org.eclipse.jdt.internal.core.util.Util;
37 import org.eclipse.jface.text.BadLocationException;
38 import org.eclipse.jface.text.IDocument;
39 import org.eclipse.text.edits.MalformedTreeException;
40 import org.eclipse.text.edits.TextEdit;
41 import org.eclipse.text.edits.UndoEdit;
42 
43 /**
44  * @see ICompilationUnit
45  */
46 @SuppressWarnings({"rawtypes", "unchecked"})
47 public class CompilationUnit extends Openable implements ICompilationUnit, org.eclipse.jdt.internal.compiler.env.ICompilationUnit, SuffixConstants {
48 	/**
49 	 * Internal synonym for deprecated constant AST.JSL2
50 	 * to alleviate deprecation warnings.
51 	 * @deprecated
52 	 */
53 	/*package*/ static final int JLS2_INTERNAL = AST.JLS2;
54 
55 	private static final IImportDeclaration[] NO_IMPORTS = new IImportDeclaration[0];
56 
57 	protected String name;
58 	public WorkingCopyOwner owner;
59 
60 /**
61  * Constructs a handle to a compilation unit with the given name in the
62  * specified package for the specified owner
63  */
CompilationUnit(PackageFragment parent, String name, WorkingCopyOwner owner)64 public CompilationUnit(PackageFragment parent, String name, WorkingCopyOwner owner) {
65 	super(parent);
66 	this.name = name;
67 	this.owner = owner;
68 }
69 
70 
71 @Override
applyTextEdit(TextEdit edit, IProgressMonitor monitor)72 public UndoEdit applyTextEdit(TextEdit edit, IProgressMonitor monitor) throws JavaModelException {
73 	IBuffer buffer = getBuffer();
74 	if (buffer instanceof IBuffer.ITextEditCapability) {
75 		return ((IBuffer.ITextEditCapability) buffer).applyTextEdit(edit, monitor);
76 	} else if (buffer != null) {
77 		IDocument document = buffer instanceof IDocument ? (IDocument) buffer : new DocumentAdapter(buffer);
78 		try {
79 			UndoEdit undoEdit= edit.apply(document);
80 			return undoEdit;
81 		} catch (MalformedTreeException | BadLocationException e) {
82 			throw new JavaModelException(e, IJavaModelStatusConstants.BAD_TEXT_EDIT_LOCATION);
83 		}
84 	}
85 	return null; // can not happen, there are no compilation units without buffer
86 }
87 
88 @Override
becomeWorkingCopy(IProblemRequestor problemRequestor, IProgressMonitor monitor)89 public void becomeWorkingCopy(IProblemRequestor problemRequestor, IProgressMonitor monitor) throws JavaModelException {
90 	JavaModelManager manager = JavaModelManager.getJavaModelManager();
91 	JavaModelManager.PerWorkingCopyInfo perWorkingCopyInfo = manager.getPerWorkingCopyInfo(this, false/*don't create*/, true /*record usage*/, null/*no problem requestor needed*/);
92 	if (perWorkingCopyInfo == null) {
93 		// close cu and its children
94 		close();
95 
96 		BecomeWorkingCopyOperation operation = new BecomeWorkingCopyOperation(this, problemRequestor);
97 		operation.runOperation(monitor);
98 	}
99 }
100 
101 @Override
becomeWorkingCopy(IProgressMonitor monitor)102 public void becomeWorkingCopy(IProgressMonitor monitor) throws JavaModelException {
103 	IProblemRequestor requestor = this.owner == null ? null : this.owner.getProblemRequestor(this);
104 	becomeWorkingCopy(requestor, monitor);
105 }
106 @Override
buildStructure(OpenableElementInfo info, final IProgressMonitor pm, Map newElements, IResource underlyingResource)107 protected boolean buildStructure(OpenableElementInfo info, final IProgressMonitor pm, Map newElements, IResource underlyingResource) throws JavaModelException {
108 	CompilationUnitElementInfo unitInfo = (CompilationUnitElementInfo) info;
109 
110 	// ensure buffer is opened
111 	IBuffer buffer = getBufferManager().getBuffer(CompilationUnit.this);
112 	if (buffer == null) {
113 		openBuffer(pm, unitInfo); // open buffer independently from the info, since we are building the info
114 	}
115 
116 	// generate structure and compute syntax problems if needed
117 	CompilationUnitStructureRequestor requestor = new CompilationUnitStructureRequestor(this, unitInfo, newElements);
118 	JavaModelManager.PerWorkingCopyInfo perWorkingCopyInfo = getPerWorkingCopyInfo();
119 	IJavaProject project = getJavaProject();
120 
121 	boolean createAST;
122 	boolean resolveBindings;
123 	int reconcileFlags;
124 	HashMap problems;
125 	if (info instanceof ASTHolderCUInfo) {
126 		ASTHolderCUInfo astHolder = (ASTHolderCUInfo) info;
127 		createAST = astHolder.astLevel != NO_AST;
128 		resolveBindings = astHolder.resolveBindings;
129 		reconcileFlags = astHolder.reconcileFlags;
130 		problems = astHolder.problems;
131 	} else {
132 		createAST = false;
133 		resolveBindings = false;
134 		reconcileFlags = 0;
135 		problems = null;
136 	}
137 
138 	boolean computeProblems = perWorkingCopyInfo != null && perWorkingCopyInfo.isActive() && project != null && JavaProject.hasJavaNature(project.getProject());
139 	IProblemFactory problemFactory = new DefaultProblemFactory();
140 	Map options = project == null ? JavaCore.getOptions() : project.getOptions(true);
141 	if (!computeProblems) {
142 		// disable task tags checking to speed up parsing
143 		options.put(JavaCore.COMPILER_TASK_TAGS, ""); //$NON-NLS-1$
144 	}
145 	CompilerOptions compilerOptions = new CompilerOptions(options);
146 	compilerOptions.ignoreMethodBodies = (reconcileFlags & ICompilationUnit.IGNORE_METHOD_BODIES) != 0;
147 	SourceElementParser parser = new SourceElementParser(
148 		requestor,
149 		problemFactory,
150 		compilerOptions,
151 		true/*report local declarations*/,
152 		!createAST /*optimize string literals only if not creating a DOM AST*/);
153 	parser.reportOnlyOneSyntaxError = !computeProblems;
154 	parser.setMethodsFullRecovery(true);
155 	parser.setStatementsRecovery((reconcileFlags & ICompilationUnit.ENABLE_STATEMENTS_RECOVERY) != 0);
156 
157 	if (!computeProblems && !resolveBindings && !createAST) // disable javadoc parsing if not computing problems, not resolving and not creating ast
158 		parser.javadocParser.checkDocComment = false;
159 	requestor.parser = parser;
160 
161 	// update timestamp (might be IResource.NULL_STAMP if original does not exist)
162 	if (underlyingResource == null) {
163 		underlyingResource = getResource();
164 	}
165 	// underlying resource is null in the case of a working copy on a class file in a jar
166 	if (underlyingResource != null)
167 		unitInfo.timestamp = ((IFile)underlyingResource).getModificationStamp();
168 
169 	// compute other problems if needed
170 	CompilationUnitDeclaration compilationUnitDeclaration = null;
171 	CompilationUnit source = cloneCachingContents();
172 	try {
173 		if (computeProblems) {
174 			if (problems == null) {
175 				// report problems to the problem requestor
176 				problems = new HashMap();
177 				compilationUnitDeclaration = CompilationUnitProblemFinder.process(source, parser, this.owner, problems, createAST, reconcileFlags, pm);
178 				try {
179 					perWorkingCopyInfo.beginReporting();
180 					for (Iterator iteraror = problems.values().iterator(); iteraror.hasNext();) {
181 						CategorizedProblem[] categorizedProblems = (CategorizedProblem[]) iteraror.next();
182 						if (categorizedProblems == null) continue;
183 						for (int i = 0, length = categorizedProblems.length; i < length; i++) {
184 							perWorkingCopyInfo.acceptProblem(categorizedProblems[i]);
185 						}
186 					}
187 				} finally {
188 					perWorkingCopyInfo.endReporting();
189 				}
190 			} else {
191 				// collect problems
192 				compilationUnitDeclaration = CompilationUnitProblemFinder.process(source, parser, this.owner, problems, createAST, reconcileFlags, pm);
193 			}
194 		} else {
195 			compilationUnitDeclaration = parser.parseCompilationUnit(source, true /*full parse to find local elements*/, pm);
196 		}
197 
198 		if (createAST) {
199 			int astLevel = ((ASTHolderCUInfo) info).astLevel;
200 			org.eclipse.jdt.core.dom.CompilationUnit cu = AST.convertCompilationUnit(astLevel, compilationUnitDeclaration, options, computeProblems, source, reconcileFlags, pm);
201 			((ASTHolderCUInfo) info).ast = cu;
202 		}
203 	} finally {
204 	    if (compilationUnitDeclaration != null) {
205 	    	unitInfo.hasFunctionalTypes = compilationUnitDeclaration.hasFunctionalTypes();
206 	        compilationUnitDeclaration.cleanUp();
207 	    }
208 	}
209 
210 	return unitInfo.isStructureKnown();
211 }
212 /*
213  * Clone this handle so that it caches its contents in memory.
214  * DO NOT PASS TO CLIENTS
215  */
cloneCachingContents()216 public CompilationUnit cloneCachingContents() {
217 	return new CompilationUnit((PackageFragment) this.parent, this.name, this.owner) {
218 		private char[] cachedContents;
219 		@Override
220 		public char[] getContents() {
221 			if (this.cachedContents == null)
222 				this.cachedContents = CompilationUnit.this.getContents();
223 			return this.cachedContents;
224 		}
225 		@Override
226 		public CompilationUnit originalFromClone() {
227 			return CompilationUnit.this;
228 		}
229 	};
230 }
231 
232 @Override
canBeRemovedFromCache()233 public boolean canBeRemovedFromCache() {
234 	if (getPerWorkingCopyInfo() != null) return false; // working copies should remain in the cache until they are destroyed
235 	return super.canBeRemovedFromCache();
236 }
237 
238 @Override
canBufferBeRemovedFromCache(IBuffer buffer)239 public boolean canBufferBeRemovedFromCache(IBuffer buffer) {
240 	if (getPerWorkingCopyInfo() != null) return false; // working copy buffers should remain in the cache until working copy is destroyed
241 	return super.canBufferBeRemovedFromCache(buffer);
242 }
243 
244 @Override
close()245 public void close() throws JavaModelException {
246 	if (getPerWorkingCopyInfo() != null) return; // a working copy must remain opened until it is discarded
247 	super.close();
248 }
249 
250 @Override
closing(Object info)251 protected void closing(Object info) {
252 	if (getPerWorkingCopyInfo() == null) {
253 		super.closing(info);
254 	} // else the buffer of a working copy must remain open for the lifetime of the working copy
255 }
256 /**
257  * @see ICodeAssist#codeComplete(int, ICompletionRequestor)
258  * @deprecated
259  */
260 @Override
codeComplete(int offset, ICompletionRequestor requestor)261 public void codeComplete(int offset, ICompletionRequestor requestor) throws JavaModelException {
262 	codeComplete(offset, requestor, DefaultWorkingCopyOwner.PRIMARY);
263 }
264 /**
265  * @see ICodeAssist#codeComplete(int, ICompletionRequestor, WorkingCopyOwner)
266  * @deprecated
267  */
268 @Override
codeComplete(int offset, ICompletionRequestor requestor, WorkingCopyOwner workingCopyOwner)269 public void codeComplete(int offset, ICompletionRequestor requestor, WorkingCopyOwner workingCopyOwner) throws JavaModelException {
270 	if (requestor == null) {
271 		throw new IllegalArgumentException("Completion requestor cannot be null"); //$NON-NLS-1$
272 	}
273 	codeComplete(offset, new org.eclipse.jdt.internal.codeassist.CompletionRequestorWrapper(requestor), workingCopyOwner);
274 }
275 /**
276  * @see ICodeAssist#codeComplete(int, ICodeCompletionRequestor)
277  * @deprecated - use codeComplete(int, ICompletionRequestor)
278  */
279 @Override
codeComplete(int offset, final ICodeCompletionRequestor requestor)280 public void codeComplete(int offset, final ICodeCompletionRequestor requestor) throws JavaModelException {
281 
282 	if (requestor == null){
283 		codeComplete(offset, (ICompletionRequestor)null);
284 		return;
285 	}
286 	codeComplete(
287 		offset,
288 		new ICompletionRequestor(){
289 			@Override
290 			public void acceptAnonymousType(char[] superTypePackageName,char[] superTypeName,char[][] parameterPackageNames,char[][] parameterTypeNames,char[][] parameterNames,char[] completionName,int modifiers,int completionStart,int completionEnd, int relevance){
291 				// ignore
292 			}
293 			@Override
294 			public void acceptClass(char[] packageName, char[] className, char[] completionName, int modifiers, int completionStart, int completionEnd, int relevance) {
295 				requestor.acceptClass(packageName, className, completionName, modifiers, completionStart, completionEnd);
296 			}
297 			@Override
298 			public void acceptError(IProblem error) {
299 				// was disabled in 1.0
300 			}
301 			@Override
302 			public void acceptField(char[] declaringTypePackageName, char[] declaringTypeName, char[] fieldName, char[] typePackageName, char[] typeName, char[] completionName, int modifiers, int completionStart, int completionEnd, int relevance) {
303 				requestor.acceptField(declaringTypePackageName, declaringTypeName, fieldName, typePackageName, typeName, completionName, modifiers, completionStart, completionEnd);
304 			}
305 			@Override
306 			public void acceptInterface(char[] packageName,char[] interfaceName,char[] completionName,int modifiers,int completionStart,int completionEnd, int relevance) {
307 				requestor.acceptInterface(packageName, interfaceName, completionName, modifiers, completionStart, completionEnd);
308 			}
309 			@Override
310 			public void acceptKeyword(char[] keywordName,int completionStart,int completionEnd, int relevance){
311 				requestor.acceptKeyword(keywordName, completionStart, completionEnd);
312 			}
313 			@Override
314 			public void acceptLabel(char[] labelName,int completionStart,int completionEnd, int relevance){
315 				requestor.acceptLabel(labelName, completionStart, completionEnd);
316 			}
317 			@Override
318 			public void acceptLocalVariable(char[] localVarName,char[] typePackageName,char[] typeName,int modifiers,int completionStart,int completionEnd, int relevance){
319 				// ignore
320 			}
321 			@Override
322 			public void acceptMethod(char[] declaringTypePackageName,char[] declaringTypeName,char[] selector,char[][] parameterPackageNames,char[][] parameterTypeNames,char[][] parameterNames,char[] returnTypePackageName,char[] returnTypeName,char[] completionName,int modifiers,int completionStart,int completionEnd, int relevance){
323 				// skip parameter names
324 				requestor.acceptMethod(declaringTypePackageName, declaringTypeName, selector, parameterPackageNames, parameterTypeNames, returnTypePackageName, returnTypeName, completionName, modifiers, completionStart, completionEnd);
325 			}
326 			@Override
327 			public void acceptMethodDeclaration(char[] declaringTypePackageName,char[] declaringTypeName,char[] selector,char[][] parameterPackageNames,char[][] parameterTypeNames,char[][] parameterNames,char[] returnTypePackageName,char[] returnTypeName,char[] completionName,int modifiers,int completionStart,int completionEnd, int relevance){
328 				// ignore
329 			}
330 			@Override
331 			public void acceptModifier(char[] modifierName,int completionStart,int completionEnd, int relevance){
332 				requestor.acceptModifier(modifierName, completionStart, completionEnd);
333 			}
334 			@Override
335 			public void acceptPackage(char[] packageName,char[] completionName,int completionStart,int completionEnd, int relevance){
336 				requestor.acceptPackage(packageName, completionName, completionStart, completionEnd);
337 			}
338 			@Override
339 			public void acceptType(char[] packageName,char[] typeName,char[] completionName,int completionStart,int completionEnd, int relevance){
340 				requestor.acceptType(packageName, typeName, completionName, completionStart, completionEnd);
341 			}
342 			@Override
343 			public void acceptVariableName(char[] typePackageName,char[] typeName,char[] varName,char[] completionName,int completionStart,int completionEnd, int relevance){
344 				// ignore
345 			}
346 		});
347 }
348 
349 @Override
codeComplete(int offset, CompletionRequestor requestor)350 public void codeComplete(int offset, CompletionRequestor requestor) throws JavaModelException {
351 	codeComplete(offset, requestor, DefaultWorkingCopyOwner.PRIMARY);
352 }
353 
354 @Override
codeComplete(int offset, CompletionRequestor requestor, IProgressMonitor monitor)355 public void codeComplete(int offset, CompletionRequestor requestor, IProgressMonitor monitor) throws JavaModelException {
356 	codeComplete(offset, requestor, DefaultWorkingCopyOwner.PRIMARY, monitor);
357 }
358 
359 @Override
codeComplete(int offset, CompletionRequestor requestor, WorkingCopyOwner workingCopyOwner)360 public void codeComplete(int offset, CompletionRequestor requestor, WorkingCopyOwner workingCopyOwner) throws JavaModelException {
361 	codeComplete(offset, requestor, workingCopyOwner, null);
362 }
363 
364 @Override
codeComplete(int offset, CompletionRequestor requestor, WorkingCopyOwner workingCopyOwner, IProgressMonitor monitor)365 public void codeComplete(int offset, CompletionRequestor requestor, WorkingCopyOwner workingCopyOwner, IProgressMonitor monitor) throws JavaModelException {
366 	codeComplete(
367 			this,
368 			isWorkingCopy() ? (org.eclipse.jdt.internal.compiler.env.ICompilationUnit) getOriginalElement() : this,
369 			offset,
370 			requestor,
371 			workingCopyOwner,
372 			this,
373 			monitor);
374 }
375 
376 /**
377  * @see ICodeAssist#codeSelect(int, int)
378  */
379 @Override
codeSelect(int offset, int length)380 public IJavaElement[] codeSelect(int offset, int length) throws JavaModelException {
381 	return codeSelect(offset, length, DefaultWorkingCopyOwner.PRIMARY);
382 }
383 /**
384  * @see ICodeAssist#codeSelect(int, int, WorkingCopyOwner)
385  */
386 @Override
codeSelect(int offset, int length, WorkingCopyOwner workingCopyOwner)387 public IJavaElement[] codeSelect(int offset, int length, WorkingCopyOwner workingCopyOwner) throws JavaModelException {
388 	return super.codeSelect(this, offset, length, workingCopyOwner);
389 }
390 /**
391  * @see IWorkingCopy#commit(boolean, IProgressMonitor)
392  * @deprecated
393  */
394 @Override
commit(boolean force, IProgressMonitor monitor)395 public void commit(boolean force, IProgressMonitor monitor) throws JavaModelException {
396 	commitWorkingCopy(force, monitor);
397 }
398 /**
399  * @see ICompilationUnit#commitWorkingCopy(boolean, IProgressMonitor)
400  */
401 @Override
commitWorkingCopy(boolean force, IProgressMonitor monitor)402 public void commitWorkingCopy(boolean force, IProgressMonitor monitor) throws JavaModelException {
403 	CommitWorkingCopyOperation op= new CommitWorkingCopyOperation(this, force);
404 	op.runOperation(monitor);
405 }
406 /**
407  * @see ISourceManipulation#copy(IJavaElement, IJavaElement, String, boolean, IProgressMonitor)
408  */
409 @Override
copy(IJavaElement container, IJavaElement sibling, String rename, boolean force, IProgressMonitor monitor)410 public void copy(IJavaElement container, IJavaElement sibling, String rename, boolean force, IProgressMonitor monitor) throws JavaModelException {
411 	if (container == null) {
412 		throw new IllegalArgumentException(Messages.operation_nullContainer);
413 	}
414 	IJavaElement[] elements = new IJavaElement[] {this};
415 	IJavaElement[] containers = new IJavaElement[] {container};
416 	String[] renamings = null;
417 	if (rename != null) {
418 		renamings = new String[] {rename};
419 	}
420 	getJavaModel().copy(elements, containers, null, renamings, force, monitor);
421 }
422 /**
423  * Returns a new element info for this element.
424  */
425 @Override
createElementInfo()426 protected Object createElementInfo() {
427 	return new CompilationUnitElementInfo();
428 }
429 /**
430  * @see ICompilationUnit#createImport(String, IJavaElement, IProgressMonitor)
431  */
432 @Override
createImport(String importName, IJavaElement sibling, IProgressMonitor monitor)433 public IImportDeclaration createImport(String importName, IJavaElement sibling, IProgressMonitor monitor) throws JavaModelException {
434 	return createImport(importName, sibling, Flags.AccDefault, monitor);
435 }
436 
437 /**
438  * @see ICompilationUnit#createImport(String, IJavaElement, int, IProgressMonitor)
439  * @since 3.0
440  */
441 @Override
createImport(String importName, IJavaElement sibling, int flags, IProgressMonitor monitor)442 public IImportDeclaration createImport(String importName, IJavaElement sibling, int flags, IProgressMonitor monitor) throws JavaModelException {
443 	CreateImportOperation op = new CreateImportOperation(importName, this, flags);
444 	if (sibling != null) {
445 		op.createBefore(sibling);
446 	}
447 	op.runOperation(monitor);
448 	return getImport(importName);
449 }
450 
451 /**
452  * @see ICompilationUnit#createPackageDeclaration(String, IProgressMonitor)
453  */
454 @Override
createPackageDeclaration(String pkg, IProgressMonitor monitor)455 public IPackageDeclaration createPackageDeclaration(String pkg, IProgressMonitor monitor) throws JavaModelException {
456 
457 	CreatePackageDeclarationOperation op= new CreatePackageDeclarationOperation(pkg, this);
458 	op.runOperation(monitor);
459 	return getPackageDeclaration(pkg);
460 }
461 /**
462  * @see ICompilationUnit#createType(String, IJavaElement, boolean, IProgressMonitor)
463  */
464 @Override
createType(String content, IJavaElement sibling, boolean force, IProgressMonitor monitor)465 public IType createType(String content, IJavaElement sibling, boolean force, IProgressMonitor monitor) throws JavaModelException {
466 	if (!exists()) {
467 		//autogenerate this compilation unit
468 		IPackageFragment pkg = (IPackageFragment) getParent();
469 		String source = ""; //$NON-NLS-1$
470 		if (!pkg.isDefaultPackage()) {
471 			//not the default package...add the package declaration
472 			String lineSeparator = Util.getLineSeparator(null/*no existing source*/, getJavaProject());
473 			source = "package " + pkg.getElementName() + ";"  + lineSeparator + lineSeparator; //$NON-NLS-1$ //$NON-NLS-2$
474 		}
475 		CreateCompilationUnitOperation op = new CreateCompilationUnitOperation(pkg, this.name, source, force);
476 		op.runOperation(monitor);
477 	}
478 	CreateTypeOperation op = new CreateTypeOperation(this, content, force);
479 	if (sibling != null) {
480 		op.createBefore(sibling);
481 	}
482 	op.runOperation(monitor);
483 	return (IType) op.getResultElements()[0];
484 }
485 /**
486  * @see ISourceManipulation#delete(boolean, IProgressMonitor)
487  */
488 @Override
delete(boolean force, IProgressMonitor monitor)489 public void delete(boolean force, IProgressMonitor monitor) throws JavaModelException {
490 	IJavaElement[] elements= new IJavaElement[] {this};
491 	getJavaModel().delete(elements, force, monitor);
492 }
493 /**
494  * @see IWorkingCopy#destroy()
495  * @deprecated
496  */
497 @Override
destroy()498 public void destroy() {
499 	try {
500 		discardWorkingCopy();
501 	} catch (JavaModelException e) {
502 		if (JavaModelManager.VERBOSE)
503 			e.printStackTrace();
504 	}
505 }
506 
507 @Override
discardWorkingCopy()508 public void discardWorkingCopy() throws JavaModelException {
509 	// discard working copy and its children
510 	DiscardWorkingCopyOperation op = new DiscardWorkingCopyOperation(this);
511 	op.runOperation(null);
512 }
513 /**
514  * Returns true if this handle represents the same Java element
515  * as the given handle.
516  *
517  * @see Object#equals(java.lang.Object)
518  */
519 @Override
equals(Object obj)520 public boolean equals(Object obj) {
521 	if (!(obj instanceof CompilationUnit)) return false;
522 	CompilationUnit other = (CompilationUnit)obj;
523 	return this.owner.equals(other.owner) && super.equals(obj);
524 }
525 /**
526  * @see ICompilationUnit#findElements(IJavaElement)
527  */
528 @Override
findElements(IJavaElement element)529 public IJavaElement[] findElements(IJavaElement element) {
530 	if (element instanceof IType && ((IType) element).isLambda()) {
531 		return null;
532 	}
533 	ArrayList children = new ArrayList();
534 	while (element != null && element.getElementType() != IJavaElement.COMPILATION_UNIT) {
535 		children.add(element);
536 		element = element.getParent();
537 	}
538 	if (element == null) return null;
539 	IJavaElement currentElement = this;
540 	for (int i = children.size()-1; i >= 0; i--) {
541 		SourceRefElement child = (SourceRefElement)children.get(i);
542 		switch (child.getElementType()) {
543 			case IJavaElement.PACKAGE_DECLARATION:
544 				currentElement = ((ICompilationUnit)currentElement).getPackageDeclaration(child.getElementName());
545 				break;
546 			case IJavaElement.IMPORT_CONTAINER:
547 				currentElement = ((ICompilationUnit)currentElement).getImportContainer();
548 				break;
549 			case IJavaElement.IMPORT_DECLARATION:
550 				currentElement = ((IImportContainer)currentElement).getImport(child.getElementName());
551 				break;
552 			case IJavaElement.TYPE:
553 				switch (currentElement.getElementType()) {
554 					case IJavaElement.COMPILATION_UNIT:
555 						currentElement = ((ICompilationUnit)currentElement).getType(child.getElementName());
556 						break;
557 					case IJavaElement.TYPE:
558 						currentElement = ((IType)currentElement).getType(child.getElementName());
559 						break;
560 					case IJavaElement.FIELD:
561 					case IJavaElement.INITIALIZER:
562 					case IJavaElement.METHOD:
563 						currentElement =  ((IMember)currentElement).getType(child.getElementName(), child.occurrenceCount);
564 						break;
565 				}
566 				break;
567 			case IJavaElement.INITIALIZER:
568 				currentElement = ((IType)currentElement).getInitializer(child.occurrenceCount);
569 				break;
570 			case IJavaElement.FIELD:
571 				currentElement = ((IType)currentElement).getField(child.getElementName());
572 				break;
573 			case IJavaElement.METHOD:
574 				currentElement = ((IType)currentElement).getMethod(child.getElementName(), ((IMethod)child).getParameterTypes());
575 				break;
576 		}
577 
578 	}
579 	if (currentElement != null && currentElement.exists()) {
580 		return new IJavaElement[] {currentElement};
581 	} else {
582 		return null;
583 	}
584 }
585 /**
586  * @see ICompilationUnit#findPrimaryType()
587  */
588 @Override
findPrimaryType()589 public IType findPrimaryType() {
590 	String typeName = Util.getNameWithoutJavaLikeExtension(getElementName());
591 	IType primaryType= getType(typeName);
592 	if (primaryType.exists()) {
593 		return primaryType;
594 	}
595 	return null;
596 }
597 
598 /**
599  * @see IWorkingCopy#findSharedWorkingCopy(IBufferFactory)
600  * @deprecated
601  */
602 @Override
findSharedWorkingCopy(IBufferFactory factory)603 public IJavaElement findSharedWorkingCopy(IBufferFactory factory) {
604 
605 	// if factory is null, default factory must be used
606 	if (factory == null) factory = getBufferManager().getDefaultBufferFactory();
607 
608 	return findWorkingCopy(BufferFactoryWrapper.create(factory));
609 }
610 
611 /**
612  * @see ICompilationUnit#findWorkingCopy(WorkingCopyOwner)
613  */
614 @Override
findWorkingCopy(WorkingCopyOwner workingCopyOwner)615 public ICompilationUnit findWorkingCopy(WorkingCopyOwner workingCopyOwner) {
616 	CompilationUnit cu = new CompilationUnit((PackageFragment)this.parent, getElementName(), workingCopyOwner);
617 	if (workingCopyOwner == DefaultWorkingCopyOwner.PRIMARY) {
618 		return cu;
619 	} else {
620 		// must be a working copy
621 		JavaModelManager.PerWorkingCopyInfo perWorkingCopyInfo = cu.getPerWorkingCopyInfo();
622 		if (perWorkingCopyInfo != null) {
623 			return perWorkingCopyInfo.getWorkingCopy();
624 		} else {
625 			return null;
626 		}
627 	}
628 }
629 /**
630  * @see ICompilationUnit#getAllTypes()
631  */
632 @Override
getAllTypes()633 public IType[] getAllTypes() throws JavaModelException {
634 	IJavaElement[] types = getTypes();
635 	ArrayList allTypes = new ArrayList(types.length);
636 	ArrayList typesToTraverse = new ArrayList(types.length);
637 	Collections.addAll(typesToTraverse, types);
638 	while (!typesToTraverse.isEmpty()) {
639 		IType type = (IType) typesToTraverse.get(0);
640 		typesToTraverse.remove(type);
641 		allTypes.add(type);
642 		types = type.getTypes();
643 		Collections.addAll(typesToTraverse, types);
644 	}
645 	IType[] arrayOfAllTypes = new IType[allTypes.size()];
646 	allTypes.toArray(arrayOfAllTypes);
647 	return arrayOfAllTypes;
648 }
649 /**
650  * @see IMember#getCompilationUnit()
651  */
652 @Override
getCompilationUnit()653 public ICompilationUnit getCompilationUnit() {
654 	return this;
655 }
656 /**
657  * @see org.eclipse.jdt.internal.compiler.env.ICompilationUnit#getContents()
658  */
659 @Override
getContents()660 public char[] getContents() {
661 	IBuffer buffer = getBufferManager().getBuffer(this);
662 	if (buffer == null) {
663 		// no need to force opening of CU to get the content
664 		// also this cannot be a working copy, as its buffer is never closed while the working copy is alive
665 		IFile file = (IFile) getResource();
666 		// Get encoding from file
667 		String encoding;
668 		try {
669 			encoding = file.getCharset();
670 		} catch(CoreException ce) {
671 			// do not use any encoding
672 			encoding = null;
673 		}
674 		try {
675 			return Util.getResourceContentsAsCharArray(file, encoding);
676 		} catch (JavaModelException e) {
677 			if (JavaModelManager.getJavaModelManager().abortOnMissingSource.get() == Boolean.TRUE) {
678 				IOException ioException =
679 					e.getJavaModelStatus().getCode() == IJavaModelStatusConstants.IO_EXCEPTION ?
680 						(IOException)e.getException() :
681 						new IOException(e.getMessage());
682 				throw new AbortCompilationUnit(null, ioException, encoding);
683 			} else {
684 				Util.log(e, Messages.bind(Messages.file_notFound, file.getFullPath().toString()));
685 			}
686 			return CharOperation.NO_CHAR;
687 		}
688 	}
689 	char[] contents = buffer.getCharacters();
690 	if (contents == null) { // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=129814
691 		if (JavaModelManager.getJavaModelManager().abortOnMissingSource.get() == Boolean.TRUE) {
692 			IOException ioException = new IOException(Messages.buffer_closed);
693 			IFile file = (IFile) getResource();
694 			// Get encoding from file
695 			String encoding;
696 			try {
697 				encoding = file.getCharset();
698 			} catch(CoreException ce) {
699 				// do not use any encoding
700 				encoding = null;
701 			}
702 			throw new AbortCompilationUnit(null, ioException, encoding);
703 		}
704 		return CharOperation.NO_CHAR;
705 	}
706 	return contents;
707 }
708 /**
709  * A compilation unit has a corresponding resource unless it is contained
710  * in a jar.
711  *
712  * @see IJavaElement#getCorrespondingResource()
713  */
714 @Override
getCorrespondingResource()715 public IResource getCorrespondingResource() throws JavaModelException {
716 	PackageFragmentRoot root = getPackageFragmentRoot();
717 	if (root == null || root.isArchive()) {
718 		return null;
719 	} else {
720 		return getUnderlyingResource();
721 	}
722 }
723 /**
724  * @see ICompilationUnit#getElementAt(int)
725  */
726 @Override
getElementAt(int position)727 public IJavaElement getElementAt(int position) throws JavaModelException {
728 
729 	IJavaElement e= getSourceElementAt(position);
730 	if (e == this) {
731 		return null;
732 	} else {
733 		return e;
734 	}
735 }
736 @Override
getElementName()737 public String getElementName() {
738 	return this.name;
739 }
740 /**
741  * @see IJavaElement
742  */
743 @Override
getElementType()744 public int getElementType() {
745 	return COMPILATION_UNIT;
746 }
747 /**
748  * @see org.eclipse.jdt.internal.compiler.env.IDependent#getFileName()
749  */
750 @Override
getFileName()751 public char[] getFileName(){
752 	return getPath().toString().toCharArray();
753 }
754 
755 @Override
getHandleFromMemento(String token, MementoTokenizer memento, WorkingCopyOwner workingCopyOwner)756 public IJavaElement getHandleFromMemento(String token, MementoTokenizer memento, WorkingCopyOwner workingCopyOwner) {
757 	switch (token.charAt(0)) {
758 		case JEM_IMPORTDECLARATION:
759 			JavaElement container = (JavaElement)getImportContainer();
760 			return container.getHandleFromMemento(token, memento, workingCopyOwner);
761 		case JEM_PACKAGEDECLARATION:
762 			if (!memento.hasMoreTokens()) return this;
763 			String pkgName = memento.nextToken();
764 			JavaElement pkgDecl = (JavaElement)getPackageDeclaration(pkgName);
765 			return pkgDecl.getHandleFromMemento(memento, workingCopyOwner);
766 		case JEM_TYPE:
767 			if (!memento.hasMoreTokens()) return this;
768 			String typeName = memento.nextToken();
769 			JavaElement type = (JavaElement)getType(typeName);
770 			return type.getHandleFromMemento(memento, workingCopyOwner);
771 		case JEM_MODULE:
772 			if (!memento.hasMoreTokens()) return this;
773 			String modName = memento.nextToken();
774 			JavaElement mod = new SourceModule(this, modName);
775 			return mod.getHandleFromMemento(memento, workingCopyOwner);
776 	}
777 	return null;
778 }
779 
780 /**
781  * @see JavaElement#getHandleMementoDelimiter()
782  */
783 @Override
getHandleMementoDelimiter()784 protected char getHandleMementoDelimiter() {
785 	return JavaElement.JEM_COMPILATIONUNIT;
786 }
787 /**
788  * @see ICompilationUnit#getImport(String)
789  */
790 @Override
getImport(String importName)791 public IImportDeclaration getImport(String importName) {
792 	return getImportContainer().getImport(importName);
793 }
794 /**
795  * @see ICompilationUnit#getImportContainer()
796  */
797 @Override
getImportContainer()798 public IImportContainer getImportContainer() {
799 	return new ImportContainer(this);
800 }
801 
802 
803 /**
804  * @see ICompilationUnit#getImports()
805  */
806 @Override
getImports()807 public IImportDeclaration[] getImports() throws JavaModelException {
808 	IImportContainer container= getImportContainer();
809 	JavaModelManager manager = JavaModelManager.getJavaModelManager();
810 	Object info = manager.getInfo(container);
811 	if (info == null) {
812 		if (manager.getInfo(this) != null)
813 			// CU was opened, but no import container, then no imports
814 			return NO_IMPORTS;
815 		else {
816 			open(null); // force opening of CU
817 			info = manager.getInfo(container);
818 			if (info == null)
819 				// after opening, if no import container, then no imports
820 				return NO_IMPORTS;
821 		}
822 	}
823 	IJavaElement[] elements = ((ImportContainerInfo) info).children;
824 	int length = elements.length;
825 	IImportDeclaration[] imports = new IImportDeclaration[length];
826 	System.arraycopy(elements, 0, imports, 0, length);
827 	return imports;
828 }
829 /**
830  * @see IMember#getTypeRoot()
831  */
getTypeRoot()832 public ITypeRoot getTypeRoot() {
833 	return this;
834 }
835 /**
836  * @see org.eclipse.jdt.internal.compiler.env.ICompilationUnit#getMainTypeName()
837  */
838 @Override
getMainTypeName()839 public char[] getMainTypeName(){
840 	return Util.getNameWithoutJavaLikeExtension(getElementName()).toCharArray();
841 }
842 /**
843  * @see IWorkingCopy#getOriginal(IJavaElement)
844  * @deprecated
845  */
846 @Override
getOriginal(IJavaElement workingCopyElement)847 public IJavaElement getOriginal(IJavaElement workingCopyElement) {
848 	// backward compatibility
849 	if (!isWorkingCopy()) return null;
850 	CompilationUnit cu = (CompilationUnit)workingCopyElement.getAncestor(COMPILATION_UNIT);
851 	if (cu == null || !this.owner.equals(cu.owner)) {
852 		return null;
853 	}
854 
855 	return workingCopyElement.getPrimaryElement();
856 }
857 /**
858  * @see IWorkingCopy#getOriginalElement()
859  * @deprecated
860  */
861 @Override
getOriginalElement()862 public IJavaElement getOriginalElement() {
863 	// backward compatibility
864 	if (!isWorkingCopy()) return null;
865 
866 	return getPrimaryElement();
867 }
868 
869 @Override
getOwner()870 public WorkingCopyOwner getOwner() {
871 	return isPrimary() || !isWorkingCopy() ? null : this.owner;
872 }
873 /**
874  * @see ICompilationUnit#getPackageDeclaration(String)
875  */
876 @Override
getPackageDeclaration(String pkg)877 public IPackageDeclaration getPackageDeclaration(String pkg) {
878 	return new PackageDeclaration(this, pkg);
879 }
880 /**
881  * @see ICompilationUnit#getPackageDeclarations()
882  */
883 @Override
getPackageDeclarations()884 public IPackageDeclaration[] getPackageDeclarations() throws JavaModelException {
885 	ArrayList list = getChildrenOfType(PACKAGE_DECLARATION);
886 	IPackageDeclaration[] array= new IPackageDeclaration[list.size()];
887 	list.toArray(array);
888 	return array;
889 }
890 /**
891  * @see org.eclipse.jdt.internal.compiler.env.ICompilationUnit#getPackageName()
892  */
893 @Override
getPackageName()894 public char[][] getPackageName() {
895 	PackageFragment packageFragment = (PackageFragment) getParent();
896 	if (packageFragment == null) return CharOperation.NO_CHAR_CHAR;
897 	return Util.toCharArrays(packageFragment.names);
898 }
899 
900 /**
901  * @see IJavaElement#getPath()
902  */
903 @Override
getPath()904 public IPath getPath() {
905 	PackageFragmentRoot root = getPackageFragmentRoot();
906 	if (root == null) return new Path(getElementName()); // working copy not in workspace
907 	if (root.isArchive()) {
908 		return root.getPath();
909 	} else {
910 		return getParent().getPath().append(getElementName());
911 	}
912 }
913 /*
914  * Returns the per working copy info for the receiver, or null if none exist.
915  * Note: the use count of the per working copy info is NOT incremented.
916  */
getPerWorkingCopyInfo()917 public JavaModelManager.PerWorkingCopyInfo getPerWorkingCopyInfo() {
918 	return JavaModelManager.getJavaModelManager().getPerWorkingCopyInfo(this, false/*don't create*/, false/*don't record usage*/, null/*no problem requestor needed*/);
919 }
920 
921 @Override
getPrimary()922 public ICompilationUnit getPrimary() {
923 	return (ICompilationUnit)getPrimaryElement(true);
924 }
925 
926 @Override
getPrimaryElement(boolean checkOwner)927 public IJavaElement getPrimaryElement(boolean checkOwner) {
928 	if (checkOwner && isPrimary()) return this;
929 	return new CompilationUnit((PackageFragment)getParent(), getElementName(), DefaultWorkingCopyOwner.PRIMARY);
930 }
931 
932 @Override
resource(PackageFragmentRoot root)933 public IResource resource(PackageFragmentRoot root) {
934 	if (root == null) return null; // working copy not in workspace
935 	return ((IContainer) ((Openable) this.parent).resource(root)).getFile(new Path(getElementName()));
936 }
937 /**
938  * @see ISourceReference#getSource()
939  */
940 @Override
getSource()941 public String getSource() throws JavaModelException {
942 	IBuffer buffer = getBuffer();
943 	if (buffer == null) return ""; //$NON-NLS-1$
944 	return buffer.getContents();
945 }
946 /**
947  * @see ISourceReference#getSourceRange()
948  */
949 @Override
getSourceRange()950 public ISourceRange getSourceRange() throws JavaModelException {
951 	return ((CompilationUnitElementInfo) getElementInfo()).getSourceRange();
952 }
953 /**
954  * @see ICompilationUnit#getType(String)
955  */
956 @Override
getType(String typeName)957 public IType getType(String typeName) {
958 	return new SourceType(this, typeName);
959 }
960 /**
961  * @see ICompilationUnit#getTypes()
962  */
963 @Override
getTypes()964 public IType[] getTypes() throws JavaModelException {
965 	ArrayList list = getChildrenOfType(TYPE);
966 	IType[] array= new IType[list.size()];
967 	list.toArray(array);
968 	return array;
969 }
970 /**
971  * @see IJavaElement
972  */
973 @Override
getUnderlyingResource()974 public IResource getUnderlyingResource() throws JavaModelException {
975 	if (isWorkingCopy() && !isPrimary()) return null;
976 	return super.getUnderlyingResource();
977 }
978 /**
979  * @see IWorkingCopy#getSharedWorkingCopy(IProgressMonitor, IBufferFactory, IProblemRequestor)
980  * @deprecated
981  */
982 @Override
getSharedWorkingCopy(IProgressMonitor pm, IBufferFactory factory, IProblemRequestor problemRequestor)983 public IJavaElement getSharedWorkingCopy(IProgressMonitor pm, IBufferFactory factory, IProblemRequestor problemRequestor) throws JavaModelException {
984 
985 	// if factory is null, default factory must be used
986 	if (factory == null) factory = getBufferManager().getDefaultBufferFactory();
987 
988 	return getWorkingCopy(BufferFactoryWrapper.create(factory), problemRequestor, pm);
989 }
990 /**
991  * @see IWorkingCopy#getWorkingCopy()
992  * @deprecated
993  */
994 @Override
getWorkingCopy()995 public IJavaElement getWorkingCopy() throws JavaModelException {
996 	return getWorkingCopy(null);
997 }
998 /**
999  * @see ICompilationUnit#getWorkingCopy(IProgressMonitor)
1000  */
1001 @Override
getWorkingCopy(IProgressMonitor monitor)1002 public ICompilationUnit getWorkingCopy(IProgressMonitor monitor) throws JavaModelException {
1003 	return getWorkingCopy(new WorkingCopyOwner() {/*non shared working copy*/}, null/*no problem requestor*/, monitor);
1004 }
1005 /**
1006  * @see ITypeRoot#getWorkingCopy(WorkingCopyOwner, IProgressMonitor)
1007  */
1008 @Override
getWorkingCopy(WorkingCopyOwner workingCopyOwner, IProgressMonitor monitor)1009 public ICompilationUnit getWorkingCopy(WorkingCopyOwner workingCopyOwner, IProgressMonitor monitor) throws JavaModelException {
1010 	return getWorkingCopy(workingCopyOwner, null, monitor);
1011 }
1012 /**
1013  * @see IWorkingCopy#getWorkingCopy(IProgressMonitor, IBufferFactory, IProblemRequestor)
1014  * @deprecated
1015  */
1016 @Override
getWorkingCopy(IProgressMonitor monitor, IBufferFactory factory, IProblemRequestor problemRequestor)1017 public IJavaElement getWorkingCopy(IProgressMonitor monitor, IBufferFactory factory, IProblemRequestor problemRequestor) throws JavaModelException {
1018 	return getWorkingCopy(BufferFactoryWrapper.create(factory), problemRequestor, monitor);
1019 }
1020 /**
1021  * @see ICompilationUnit#getWorkingCopy(WorkingCopyOwner, IProblemRequestor, IProgressMonitor)
1022  * @deprecated
1023  */
1024 @Override
getWorkingCopy(WorkingCopyOwner workingCopyOwner, IProblemRequestor problemRequestor, IProgressMonitor monitor)1025 public ICompilationUnit getWorkingCopy(WorkingCopyOwner workingCopyOwner, IProblemRequestor problemRequestor, IProgressMonitor monitor) throws JavaModelException {
1026 	if (!isPrimary()) return this;
1027 
1028 	JavaModelManager manager = JavaModelManager.getJavaModelManager();
1029 
1030 	CompilationUnit workingCopy = new CompilationUnit((PackageFragment)getParent(), getElementName(), workingCopyOwner);
1031 	JavaModelManager.PerWorkingCopyInfo perWorkingCopyInfo =
1032 		manager.getPerWorkingCopyInfo(workingCopy, false/*don't create*/, true/*record usage*/, null/*not used since don't create*/);
1033 	if (perWorkingCopyInfo != null) {
1034 		return perWorkingCopyInfo.getWorkingCopy(); // return existing handle instead of the one created above
1035 	}
1036 	BecomeWorkingCopyOperation op = new BecomeWorkingCopyOperation(workingCopy, problemRequestor);
1037 	op.runOperation(monitor);
1038 	return workingCopy;
1039 }
1040 /**
1041  * @see Openable#hasBuffer()
1042  */
1043 @Override
hasBuffer()1044 protected boolean hasBuffer() {
1045 	return true;
1046 }
1047 
1048 @Override
hasResourceChanged()1049 public boolean hasResourceChanged() {
1050 	if (!isWorkingCopy()) return false;
1051 
1052 	// if resource got deleted, then #getModificationStamp() will answer IResource.NULL_STAMP, which is always different from the cached
1053 	// timestamp
1054 	Object info = JavaModelManager.getJavaModelManager().getInfo(this);
1055 	if (info == null) return false;
1056 	IResource resource = getResource();
1057 	if (resource == null) return false;
1058 	return ((CompilationUnitElementInfo)info).timestamp != resource.getModificationStamp();
1059 }
1060 @Override
ignoreOptionalProblems()1061 public boolean ignoreOptionalProblems() {
1062 	return getPackageFragmentRoot().ignoreOptionalProblems();
1063 }
1064 /**
1065  * @see IWorkingCopy#isBasedOn(IResource)
1066  * @deprecated
1067  */
1068 @Override
isBasedOn(IResource resource)1069 public boolean isBasedOn(IResource resource) {
1070 	if (!isWorkingCopy()) return false;
1071 	if (!getResource().equals(resource)) return false;
1072 	return !hasResourceChanged();
1073 }
1074 /**
1075  * @see IOpenable#isConsistent()
1076  */
1077 @Override
isConsistent()1078 public boolean isConsistent() {
1079 	return !JavaModelManager.getJavaModelManager().getElementsOutOfSynchWithBuffers().contains(this);
1080 }
isPrimary()1081 public boolean isPrimary() {
1082 	return this.owner == DefaultWorkingCopyOwner.PRIMARY;
1083 }
1084 /**
1085  * @see Openable#isSourceElement()
1086  */
1087 @Override
isSourceElement()1088 protected boolean isSourceElement() {
1089 	return true;
1090 }
validateCompilationUnit(IResource resource)1091 protected IStatus validateCompilationUnit(IResource resource) {
1092 	IPackageFragmentRoot root = getPackageFragmentRoot();
1093 	// root never null as validation is not done for working copies
1094 	try {
1095 		if (root.getKind() != IPackageFragmentRoot.K_SOURCE)
1096 			return new JavaModelStatus(IJavaModelStatusConstants.INVALID_ELEMENT_TYPES, root);
1097 	} catch (JavaModelException e) {
1098 		return e.getJavaModelStatus();
1099 	}
1100 	if (resource != null) {
1101 		char[][] inclusionPatterns = ((PackageFragmentRoot)root).fullInclusionPatternChars();
1102 		char[][] exclusionPatterns = ((PackageFragmentRoot)root).fullExclusionPatternChars();
1103 		if (Util.isExcluded(resource, inclusionPatterns, exclusionPatterns))
1104 			return new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_NOT_ON_CLASSPATH, this);
1105 		if (!resource.isAccessible())
1106 			return new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this);
1107 	}
1108 	IJavaProject project = getJavaProject();
1109 	return JavaConventions.validateCompilationUnitName(getElementName(),project.getOption(JavaCore.COMPILER_SOURCE, true), project.getOption(JavaCore.COMPILER_COMPLIANCE, true));
1110 }
1111 
1112 @Override
isWorkingCopy()1113 public boolean isWorkingCopy() {
1114 	// For backward compatibility, non primary working copies are always returning true; in removal
1115 	// delta, clients can still check that element was a working copy before being discarded.
1116 	return !isPrimary() || getPerWorkingCopyInfo() != null;
1117 }
1118 /**
1119  * @see IOpenable#makeConsistent(IProgressMonitor)
1120  */
1121 @Override
makeConsistent(IProgressMonitor monitor)1122 public void makeConsistent(IProgressMonitor monitor) throws JavaModelException {
1123 	makeConsistent(NO_AST, false/*don't resolve bindings*/, 0 /* don't perform statements recovery */, null/*don't collect problems but report them*/, monitor);
1124 }
makeConsistent(int astLevel, boolean resolveBindings, int reconcileFlags, HashMap problems, IProgressMonitor monitor)1125 public org.eclipse.jdt.core.dom.CompilationUnit makeConsistent(int astLevel, boolean resolveBindings, int reconcileFlags, HashMap problems, IProgressMonitor monitor) throws JavaModelException {
1126 	if (isConsistent()) return null;
1127 
1128 	try {
1129 		JavaModelManager.getJavaModelManager().abortOnMissingSource.set(Boolean.TRUE);
1130 		// create a new info and make it the current info
1131 		// (this will remove the info and its children just before storing the new infos)
1132 		if (astLevel != NO_AST || problems != null) {
1133 			ASTHolderCUInfo info = new ASTHolderCUInfo();
1134 			info.astLevel = astLevel;
1135 			info.resolveBindings = resolveBindings;
1136 			info.reconcileFlags = reconcileFlags;
1137 			info.problems = problems;
1138 			openWhenClosed(info, true, monitor);
1139 			org.eclipse.jdt.core.dom.CompilationUnit result = info.ast;
1140 			info.ast = null;
1141 			return result;
1142 		} else {
1143 			openWhenClosed(createElementInfo(), true, monitor);
1144 			return null;
1145 		}
1146 	} finally {
1147 		JavaModelManager.getJavaModelManager().abortOnMissingSource.set(null);
1148 	}
1149 }
1150 /**
1151  * @see ISourceManipulation#move(IJavaElement, IJavaElement, String, boolean, IProgressMonitor)
1152  */
1153 @Override
move(IJavaElement container, IJavaElement sibling, String rename, boolean force, IProgressMonitor monitor)1154 public void move(IJavaElement container, IJavaElement sibling, String rename, boolean force, IProgressMonitor monitor) throws JavaModelException {
1155 	if (container == null) {
1156 		throw new IllegalArgumentException(Messages.operation_nullContainer);
1157 	}
1158 	IJavaElement[] elements= new IJavaElement[] {this};
1159 	IJavaElement[] containers= new IJavaElement[] {container};
1160 
1161 	String[] renamings= null;
1162 	if (rename != null) {
1163 		renamings= new String[] {rename};
1164 	}
1165 	getJavaModel().move(elements, containers, null, renamings, force, monitor);
1166 }
1167 
1168 /**
1169  * @see Openable#openBuffer(IProgressMonitor, Object)
1170  */
1171 @Override
openBuffer(IProgressMonitor pm, Object info)1172 protected IBuffer openBuffer(IProgressMonitor pm, Object info) throws JavaModelException {
1173 
1174 	// create buffer
1175 	BufferManager bufManager = getBufferManager();
1176 	boolean isWorkingCopy = isWorkingCopy();
1177 	IBuffer buffer =
1178 		isWorkingCopy
1179 			? this.owner.createBuffer(this)
1180 			: BufferManager.createBuffer(this);
1181 	if (buffer == null) return null;
1182 
1183 	ICompilationUnit original = null;
1184 	boolean mustSetToOriginalContent = false;
1185 	if (isWorkingCopy) {
1186 		// ensure that isOpen() is called outside the bufManager synchronized block
1187 		// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=237772
1188 		mustSetToOriginalContent = !isPrimary() && (original = new CompilationUnit((PackageFragment)getParent(), getElementName(), DefaultWorkingCopyOwner.PRIMARY)).isOpen() ;
1189 	}
1190 
1191 	// synchronize to ensure that 2 threads are not putting 2 different buffers at the same time
1192 	// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=146331
1193 	IBuffer existingBuffer;
1194 	synchronized(bufManager) {
1195 		existingBuffer = bufManager.getBuffer(this);
1196 		if (existingBuffer == null) {
1197 			// set the buffer source
1198 			if (buffer.getCharacters() == null) {
1199 				if (isWorkingCopy) {
1200 					if (mustSetToOriginalContent) {
1201 						buffer.setContents(original.getSource());
1202 					} else {
1203 						IFile file = (IFile)getResource();
1204 						if (file == null || !file.exists()) {
1205 							// initialize buffer with empty contents
1206 							buffer.setContents(CharOperation.NO_CHAR);
1207 						} else {
1208 							buffer.setContents(Util.getResourceContentsAsCharArray(file));
1209 						}
1210 					}
1211 				} else {
1212 					IFile file = (IFile)getResource();
1213 					if (file == null || !file.exists()) throw newNotPresentException();
1214 					buffer.setContents(Util.getResourceContentsAsCharArray(file));
1215 				}
1216 			}
1217 
1218 			// add buffer to buffer cache
1219 			// note this may cause existing buffers to be removed from the buffer cache, but only primary compilation unit's buffer
1220 			// can be closed, thus no call to a client's IBuffer#close() can be done in this synchronized block.
1221 			bufManager.addBuffer(buffer);
1222 
1223 			// listen to buffer changes
1224 			buffer.addBufferChangedListener(this);
1225 		}
1226 	}
1227 	if(existingBuffer != null) {
1228 		buffer.close();
1229 		return existingBuffer;
1230 	}
1231 	return buffer;
1232 }
1233 @Override
openAncestors(HashMap newElements, IProgressMonitor monitor)1234 protected void openAncestors(HashMap newElements, IProgressMonitor monitor) throws JavaModelException {
1235 	if (!isWorkingCopy()) {
1236 		super.openAncestors(newElements, monitor);
1237 	}
1238 	// else don't open ancestors for a working copy to speed up the first becomeWorkingCopy
1239 	// (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=89411)
1240 }
1241 /*
1242  * @see #cloneCachingContents()
1243  */
originalFromClone()1244 public CompilationUnit originalFromClone() {
1245 	return this;
1246 }
1247 /**
1248  * @see ICompilationUnit#reconcile()
1249  * @deprecated
1250  */
1251 @Override
reconcile()1252 public IMarker[] reconcile() throws JavaModelException {
1253 	reconcile(NO_AST, false/*don't force problem detection*/, false, null/*use primary owner*/, null/*no progress monitor*/);
1254 	return null;
1255 }
1256 /**
1257  * @see ICompilationUnit#reconcile(int, boolean, WorkingCopyOwner, IProgressMonitor)
1258  */
1259 @Override
reconcile(boolean forceProblemDetection, IProgressMonitor monitor)1260 public void reconcile(boolean forceProblemDetection, IProgressMonitor monitor) throws JavaModelException {
1261 	reconcile(NO_AST, forceProblemDetection? ICompilationUnit.FORCE_PROBLEM_DETECTION : 0, null/*use primary owner*/, monitor);
1262 }
1263 
1264 /**
1265  * @see ICompilationUnit#reconcile(int, boolean, WorkingCopyOwner, IProgressMonitor)
1266  * @since 3.0
1267  */
1268 @Override
reconcile( int astLevel, boolean forceProblemDetection, WorkingCopyOwner workingCopyOwner, IProgressMonitor monitor)1269 public org.eclipse.jdt.core.dom.CompilationUnit reconcile(
1270 		int astLevel,
1271 		boolean forceProblemDetection,
1272 		WorkingCopyOwner workingCopyOwner,
1273 		IProgressMonitor monitor) throws JavaModelException {
1274 	return reconcile(astLevel, forceProblemDetection? ICompilationUnit.FORCE_PROBLEM_DETECTION : 0, workingCopyOwner, monitor);
1275 }
1276 
1277 /**
1278  * @see ICompilationUnit#reconcile(int, boolean, WorkingCopyOwner, IProgressMonitor)
1279  * @since 3.0
1280  */
1281 @Override
reconcile( int astLevel, boolean forceProblemDetection, boolean enableStatementsRecovery, WorkingCopyOwner workingCopyOwner, IProgressMonitor monitor)1282 public org.eclipse.jdt.core.dom.CompilationUnit reconcile(
1283 		int astLevel,
1284 		boolean forceProblemDetection,
1285 		boolean enableStatementsRecovery,
1286 		WorkingCopyOwner workingCopyOwner,
1287 		IProgressMonitor monitor) throws JavaModelException {
1288 	int flags = 0;
1289 	if (forceProblemDetection) flags |= ICompilationUnit.FORCE_PROBLEM_DETECTION;
1290 	if (enableStatementsRecovery) flags |= ICompilationUnit.ENABLE_STATEMENTS_RECOVERY;
1291 	return reconcile(astLevel, flags, workingCopyOwner, monitor);
1292 }
1293 
1294 @Override
reconcile( int astLevel, int reconcileFlags, WorkingCopyOwner workingCopyOwner, IProgressMonitor monitor)1295 public org.eclipse.jdt.core.dom.CompilationUnit reconcile(
1296 		int astLevel,
1297 		int reconcileFlags,
1298 		WorkingCopyOwner workingCopyOwner,
1299 		IProgressMonitor monitor)
1300 		throws JavaModelException {
1301 
1302 	if (!isWorkingCopy()) return null; // Reconciling is not supported on non working copies
1303 	if (workingCopyOwner == null) workingCopyOwner = DefaultWorkingCopyOwner.PRIMARY;
1304 
1305 
1306 	PerformanceStats stats = null;
1307 	if(ReconcileWorkingCopyOperation.PERF) {
1308 		stats = PerformanceStats.getStats(JavaModelManager.RECONCILE_PERF, this);
1309 		stats.startRun(new String(getFileName()));
1310 	}
1311 	ReconcileWorkingCopyOperation op = new ReconcileWorkingCopyOperation(this, astLevel, reconcileFlags, workingCopyOwner);
1312 	JavaModelManager manager = JavaModelManager.getJavaModelManager();
1313 	try {
1314 		manager.cacheZipFiles(this); // cache zip files for performance (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=134172)
1315 		op.runOperation(monitor);
1316 	} finally {
1317 		manager.flushZipFiles(this);
1318 	}
1319 	if(ReconcileWorkingCopyOperation.PERF) {
1320 		stats.endRun();
1321 	}
1322 	return op.ast;
1323 }
1324 
1325 /**
1326  * @see ISourceManipulation#rename(String, boolean, IProgressMonitor)
1327  */
1328 @Override
rename(String newName, boolean force, IProgressMonitor monitor)1329 public void rename(String newName, boolean force, IProgressMonitor monitor) throws JavaModelException {
1330 	if (newName == null) {
1331 		throw new IllegalArgumentException(Messages.operation_nullName);
1332 	}
1333 	IJavaElement[] elements= new IJavaElement[] {this};
1334 	IJavaElement[] dests= new IJavaElement[] {getParent()};
1335 	String[] renamings= new String[] {newName};
1336 	getJavaModel().rename(elements, dests, renamings, force, monitor);
1337 }
1338 
1339 @Override
restore()1340 public void restore() throws JavaModelException {
1341 
1342 	if (!isWorkingCopy()) return;
1343 
1344 	CompilationUnit original = (CompilationUnit) getOriginalElement();
1345 	IBuffer buffer = getBuffer();
1346 	if (buffer == null) return;
1347 	buffer.setContents(original.getContents());
1348 	updateTimeStamp(original);
1349 	makeConsistent(null);
1350 }
1351 /**
1352  * @see IOpenable
1353  */
1354 @Override
save(IProgressMonitor pm, boolean force)1355 public void save(IProgressMonitor pm, boolean force) throws JavaModelException {
1356 	if (isWorkingCopy()) {
1357 		// no need to save the buffer for a working copy (this is a noop)
1358 		reconcile();   // not simply makeConsistent, also computes fine-grain deltas
1359 								// in case the working copy is being reconciled already (if not it would miss
1360 								// one iteration of deltas).
1361 	} else {
1362 		super.save(pm, force);
1363 	}
1364 }
1365 /**
1366  * Debugging purposes
1367  */
1368 @Override
toStringInfo(int tab, StringBuffer buffer, Object info, boolean showResolvedInfo)1369 protected void toStringInfo(int tab, StringBuffer buffer, Object info, boolean showResolvedInfo) {
1370 	if (!isPrimary()) {
1371 		buffer.append(tabString(tab));
1372 		buffer.append("[Working copy] "); //$NON-NLS-1$
1373 		toStringName(buffer);
1374 	} else {
1375 		if (isWorkingCopy()) {
1376 			buffer.append(tabString(tab));
1377 			buffer.append("[Working copy] "); //$NON-NLS-1$
1378 			toStringName(buffer);
1379 			if (info == null) {
1380 				buffer.append(" (not open)"); //$NON-NLS-1$
1381 			}
1382 		} else {
1383 			super.toStringInfo(tab, buffer, info, showResolvedInfo);
1384 		}
1385 	}
1386 }
1387 /*
1388  * Assume that this is a working copy
1389  */
updateTimeStamp(CompilationUnit original)1390 protected void updateTimeStamp(CompilationUnit original) throws JavaModelException {
1391 	long timeStamp =
1392 		((IFile) original.getResource()).getModificationStamp();
1393 	if (timeStamp == IResource.NULL_STAMP) {
1394 		throw new JavaModelException(
1395 			new JavaModelStatus(IJavaModelStatusConstants.INVALID_RESOURCE));
1396 	}
1397 	((CompilationUnitElementInfo) getElementInfo()).timestamp = timeStamp;
1398 }
1399 
1400 @Override
validateExistence(IResource underlyingResource)1401 protected IStatus validateExistence(IResource underlyingResource) {
1402 	// check if this compilation unit can be opened
1403 	if (!isWorkingCopy()) { // no check is done on root kind or exclusion pattern for working copies
1404 		IStatus status = validateCompilationUnit(underlyingResource);
1405 		if (!status.isOK())
1406 			return status;
1407 	}
1408 
1409 	// prevents reopening of non-primary working copies (they are closed when they are discarded and should not be reopened)
1410 	if (!isPrimary() && getPerWorkingCopyInfo() == null) {
1411 		return newDoesNotExistStatus();
1412 	}
1413 
1414 	return JavaModelStatus.VERIFIED_OK;
1415 }
1416 
1417 @Override
getNameRange()1418 public ISourceRange getNameRange() {
1419 	return null;
1420 }
1421 
1422 
1423 @Override
getModule()1424 public IModuleDescription getModule() throws JavaModelException {
1425 	if (TypeConstants.MODULE_INFO_FILE_NAME_STRING.equals(getElementName()))
1426 		return ((CompilationUnitElementInfo) getElementInfo()).getModule();
1427 	return null;
1428 }
1429 
1430 @Override
getModuleName()1431 public char[] getModuleName() {
1432 	try {
1433 		IModuleDescription module = getModule();
1434 		if (module == null) {
1435 			JavaProject project = (JavaProject) getAncestor(IJavaElement.JAVA_PROJECT);
1436 			module = project.getModuleDescription();
1437 		}
1438 		if (module != null)
1439 			return module.getElementName().toCharArray();
1440 	} catch (JavaModelException e) {
1441 		// TODO Auto-generated catch block
1442 		e.printStackTrace();
1443 	}
1444 	return null;
1445 }
1446 }
1447