blob: def2cbaa0b9623bfbd7a697a9e8333bee7863a90 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2006 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Luzius Meisser - initial implementation
* Sian January - added eager parsing support
*******************************************************************************/
package org.eclipse.ajdt.core.javaelements;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.aspectj.asm.IProgramElement;
import org.eclipse.ajdt.core.AJLog;
import org.eclipse.ajdt.core.AspectJPlugin;
import org.eclipse.ajdt.core.codeconversion.AspectsConvertingParser;
import org.eclipse.ajdt.core.codeconversion.ConversionOptions;
import org.eclipse.ajdt.core.codeconversion.ITDAwareCancelableNameEnvironment;
import org.eclipse.ajdt.core.codeconversion.JavaCompatibleBuffer;
import org.eclipse.ajdt.core.codeconversion.AspectsConvertingParser.Replacement;
import org.eclipse.ajdt.core.parserbridge.AJCompilationUnitStructureRequestor;
import org.eclipse.ajdt.core.parserbridge.AJSourceElementParser;
import org.eclipse.ajdt.core.reconcile.AJReconcileWorkingCopyOperation;
import org.eclipse.ajdt.internal.core.AJWorkingCopyOwner;
import org.eclipse.ajdt.internal.core.contentassist.ProposalRequestorFilter;
import org.eclipse.ajdt.internal.core.contentassist.ProposalRequestorWrapper;
import org.eclipse.ajdt.internal.core.parserbridge.AJCompilationUnitDeclarationWrapper;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.PerformanceStats;
import org.eclipse.jdt.core.CompletionRequestor;
import org.eclipse.jdt.core.IBuffer;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaModelStatusConstants;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IProblemRequestor;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.ITypeRoot;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.core.WorkingCopyOwner;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.internal.codeassist.CompletionEngine;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.core.BecomeWorkingCopyOperation;
import org.eclipse.jdt.internal.core.BufferManager;
import org.eclipse.jdt.internal.core.CompilationUnit;
import org.eclipse.jdt.internal.core.JavaElement;
import org.eclipse.jdt.internal.core.JavaModelManager;
import org.eclipse.jdt.internal.core.JavaModelStatus;
import org.eclipse.jdt.internal.core.JavaProject;
import org.eclipse.jdt.internal.core.NameLookup;
import org.eclipse.jdt.internal.core.Openable;
import org.eclipse.jdt.internal.core.OpenableElementInfo;
import org.eclipse.jdt.internal.core.PackageFragment;
import org.eclipse.jdt.internal.core.ReconcileWorkingCopyOperation;
import org.eclipse.jdt.internal.core.SearchableEnvironment;
import org.eclipse.jdt.internal.core.SourceType;
import org.eclipse.jdt.internal.core.util.MementoTokenizer;
import org.eclipse.jdt.internal.core.util.SimpleDocument;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
/**
* An ICompilationUnit for .aj files.
*
* In order to obtain better interoperability with jdt, AJCompilationUnits pretend
* to have java syntax compatible contents. To get the real contents,
* requestOriginalContentMode()
* must be called before getting the Buffer. Please make sure to call
* discardOriginalContentMode()
* afterwards to get back into non-original mode.
*
* @author Luzius Meisser
*/
public class AJCompilationUnit extends CompilationUnit{
/**
* Cloned Unit for doing reconciling.
* Always want to use CODE_COMPLETE style of conversion
* @author andrew
*
*/
public final class ClonedAJCU extends AJCompilationUnit {
private char[] cachedFakeContents;
private IDocument cachedOrigDocument;
private ArrayList/*Replacement*/ replacements;
public ClonedAJCU(PackageFragment fragment, String elementName,
WorkingCopyOwner workingCopyOwner) {
super(fragment, elementName, workingCopyOwner);
}
public char[] getContents() {
if (this.cachedFakeContents == null) {
AJCompilationUnit.this.requestOriginalContentMode();
char[] cachedOrigContents = AJCompilationUnit.this.getContents();
AJCompilationUnit.this.discardOriginalContentMode();
cachedOrigDocument = new Document(new String(cachedOrigContents));
AspectsConvertingParser transformer = new AspectsConvertingParser(cachedOrigContents);
transformer.setUnit(AJCompilationUnit.this);
replacements = transformer.convert(ConversionOptions.CODE_COMPLETION);
this.cachedFakeContents = transformer.content;
}
return this.cachedFakeContents;
}
public CompilationUnit originalFromClone() {
return AJCompilationUnit.this;
}
public int translatePositionToReal(int pos){
return AspectsConvertingParser.translatePositionToBeforeChanges(pos, replacements, true);
}
public int getLineOfOffsetInOriginal(int offset) {
if (cachedOrigDocument != null) {
try {
return cachedOrigDocument.getLineOfOffset(offset);
} catch (BadLocationException e) {
}
}
return -1;
}
public int getColumnOfOffsetInOriginal(int offset) {
if (cachedOrigDocument != null) {
try {
IRegion region = cachedOrigDocument.getLineInformationOfOffset(offset);
return offset - region.getOffset();
} catch (BadLocationException e) {
}
}
return -1;
}
}
int originalContentMode = 0;
private IFile ajFile;
protected JavaCompatibleBuffer javaCompBuffer;
public boolean isInOriginalContentMode(){
return originalContentMode > 0;
}
/**
* ensure that the next time the buffer is asked for,
* the actual AJ contents are returned (not the
* converted contents)
*/
public synchronized void requestOriginalContentMode(){
originalContentMode++;
}
/**
* discard this request for original contents
*/
public synchronized void discardOriginalContentMode(){
originalContentMode--;
}
public AJCompilationUnit(IFile ajFile){
super(CompilationUnitTools.getParentPackage(ajFile), ajFile.getName(), AJWorkingCopyOwner.INSTANCE);
this.ajFile = ajFile;
}
/**
* @param fragment
* @param elementName
* @param workingCopyOwner
*/
public AJCompilationUnit(PackageFragment fragment, String elementName, WorkingCopyOwner workingCopyOwner) {
super(fragment, elementName, workingCopyOwner);
if(fragment.getResource() instanceof IProject) {
IProject p = (IProject)fragment.getResource();
this.ajFile = (IFile)p.findMember(elementName);
} else {
IFolder f = (IFolder)fragment.getResource();
this.ajFile = (IFile)f.findMember(elementName);
}
}
public char[] getMainTypeName(){
if (AspectJPlugin.usingCUprovider) {
return super.getMainTypeName();
}
String elementName = name;
//remove the .aj
elementName = elementName.substring(0, elementName.length() - ".aj".length()); //$NON-NLS-1$
return elementName.toCharArray();
}
/* Eclipse 3.1M3: prior to this we overrode isValidCompilationUnit, but now we need to
* override validateCompilationUnit, otherwise the check for valid name will fail on
* .aj files
*/
// protected IStatus validateCompilationUnit(IResource resource) {
// IPackageFragmentRoot root = getPackageFragmentRoot();
// try {
// if (!(resource.getProject().exists()) || root.getKind() != IPackageFragmentRoot.K_SOURCE)
// return new JavaModelStatus(IJavaModelStatusConstants.INVALID_ELEMENT_TYPES, root);
// } catch (JavaModelException e) {
// return e.getJavaModelStatus();
// }
// return JavaModelStatus.OK_STATUS;
// }
/* Eclipse 3.2M6: bypass buffer cache to ensure fake buffer is used
*/
/**
* @see org.eclipse.jdt.internal.compiler.env.ICompilationUnit#getContents()
*/
public char[] getContents() {
try {
IBuffer buffer = this.getBuffer();
return buffer == null ? CharOperation.NO_CHAR : buffer.getCharacters();
} catch (JavaModelException e) {
return CharOperation.NO_CHAR;
}
}
public IResource getResource(){
if (AspectJPlugin.usingCUprovider) {
return super.getResource();
}
return ajFile;
}
/*
* needs to return real path for organize imports
*/
public IPath getPath() {
if (AspectJPlugin.usingCUprovider || ajFile == null) {
return super.getPath();
}
return ajFile.getFullPath();
}
public IResource getUnderlyingResource() throws JavaModelException {
if (AspectJPlugin.usingCUprovider) {
return super.getUnderlyingResource();
}
return ajFile;
}
protected void generateInfos(Object info, HashMap newElements, IProgressMonitor monitor) throws JavaModelException {
if (!(info instanceof AJCompilationUnitInfo)){
info = new AJCompilationUnitInfo();
}
super.generateInfos(info, newElements, monitor);
}
/**
* builds the structure of this Compilation unit. We need to use an aspect-aware parser for this (in the org.aspectj.org.eclipse... world, which
* makes things a little messy
*/
protected boolean buildStructure(OpenableElementInfo info, final IProgressMonitor pm, Map newElements, IResource underlyingResource) throws JavaModelException {
AJCompilationUnitInfo unitInfo = (AJCompilationUnitInfo) info;
if(ajFile == null) {
return false;
}
// ensure buffer is opened
IBuffer buffer = getBufferManager().getBuffer(this);
if (buffer == null) {
openBuffer(pm, unitInfo); // open buffer independently from the info, since we are building the info
}
// generate structure and compute syntax problems if needed
AJCompilationUnitStructureRequestor requestor = new AJCompilationUnitStructureRequestor(this, unitInfo, newElements);
JavaModelManager.PerWorkingCopyInfo perWorkingCopyInfo = getPerWorkingCopyInfo();
IJavaProject project = getJavaProject();
boolean createAST;
boolean resolveBindings;
int reconcileFlags;
// HashMap problems;
AJCompilationUnitInfo astHolder = (AJCompilationUnitInfo) info;
createAST = astHolder.getASTLevel() != NO_AST;
resolveBindings = astHolder.doResolveBindings();
reconcileFlags = astHolder.getReconcileFlags();
// problems = astHolder.getProblems();
boolean computeProblems = perWorkingCopyInfo != null && perWorkingCopyInfo.isActive() && project != null &&
AspectJPlugin.isAJProject(project.getProject());
org.aspectj.org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory problemFactory =
new org.aspectj.org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory();
Map options = project == null ? JavaCore.getOptions() : project.getOptions(true);
if (!computeProblems) {
// disable task tags checking to speed up parsing
options.put(JavaCore.COMPILER_TASK_TAGS, ""); //$NON-NLS-1$
}
// ensure parser sees the real contents (not the fake java buffer)
this.requestOriginalContentMode();
// use an aspectj aware source parser
AJSourceElementParser ajdtParser = new AJSourceElementParser(
requestor,
problemFactory,
new org.aspectj.org.eclipse.jdt.internal.compiler.impl.CompilerOptions(options),
true/*report local declarations*/,
!createAST /*optimize string literals only if not creating a DOM AST*/);
ajdtParser.reportOnlyOneSyntaxError = !computeProblems;
ajdtParser.setMethodsFullRecovery(true);
ajdtParser.setStatementsRecovery((reconcileFlags & ICompilationUnit.ENABLE_STATEMENTS_RECOVERY) != 0);
if (!computeProblems && !resolveBindings && !createAST) {
// disable javadoc parsing if not computing problems, not resolving and not creating ast
ajdtParser.javadocParser.checkDocComment = false;
}
requestor.setParser(ajdtParser);
// update timestamp (might be IResource.NULL_STAMP if original does not exist)
if (underlyingResource == null) {
underlyingResource = getResource();
}
// underlying resource is null in the case of a working copy on a class file in a jar
if (underlyingResource != null)
unitInfo.setTimestamp(((IFile)underlyingResource).getModificationStamp());
// compute other problems if needed
CompilationUnitDeclaration compilationUnitDeclaration = null;
final AJCompilationUnit source = ajCloneCachingContents();
requestor.setSource(source.getContents());
try {
if (false) {
// for now, don't go here
// the problem is that we can't find problems and build structure at the same time
// they require difference kinds of parsers.
// if (computeProblems) {
// if (problems == null) {
// // report problems to the problem requestor
// problems = new HashMap();
// compilationUnitDeclaration = AJCompilationUnitProblemFinder.processAJ(
// source, ajdtParser, this.owner, problems, createAST, reconcileFlags, pm);
// try {
// perWorkingCopyInfo.beginReporting();
// for (Iterator iteraror = problems.values().iterator(); iteraror.hasNext();) {
// CategorizedProblem[] categorizedProblems = (CategorizedProblem[]) iteraror.next();
// if (categorizedProblems == null) continue;
// for (int i = 0, length = categorizedProblems.length; i < length; i++) {
// perWorkingCopyInfo.acceptProblem(categorizedProblems[i]);
// }
// }
// } finally {
// perWorkingCopyInfo.endReporting();
// }
// } else {
// // collect problems
// compilationUnitDeclaration = AJCompilationUnitProblemFinder.processAJ(source, ajdtParser, this.owner, problems, createAST, reconcileFlags, pm);
// }
} else {
// since we are doing n aspectj aware parse with the AJ parser
// need to wrap the results in a JDT CompilationUnitDeclaration
org.aspectj.org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration
ajDeclaration = ajdtParser.parseCompilationUnit(new org.aspectj.org.eclipse.jdt.internal.compiler.env.ICompilationUnit() {
public char[] getContents() {
return source.getContents();
}
public char[] getMainTypeName() {
return source.getMainTypeName();
}
public char[][] getPackageName() {
return source.getPackageName();
}
public char[] getFileName() {
return source.getFileName();
}
}, true /*full parse to find local elements*/);
compilationUnitDeclaration = new AJCompilationUnitDeclarationWrapper(ajDeclaration, source);
}
if (createAST) {
// XXX hmmmm...may not work
int astLevel = unitInfo.getASTLevel();
org.eclipse.jdt.core.dom.CompilationUnit cu = AST.convertCompilationUnit(astLevel, compilationUnitDeclaration, options, computeProblems, source, reconcileFlags, pm);
unitInfo.setAST(cu);
}
} finally {
discardOriginalContentMode();
if (compilationUnitDeclaration != null) {
compilationUnitDeclaration.cleanUp();
}
}
return unitInfo.isStructureKnown();
//
//
//
//
// try {
// // check if this compilation unit can be opened
// if (!isWorkingCopy()) { // no check is done on root kind or exclusion pattern for working copies
// IStatus status = validateCompilationUnit(underlyingResource);
// if (!status.isOK()) throw newJavaModelException(status);
// }
//
// // prevents reopening of non-primary working copies (they are closed when they are discarded and should not be reopened)
// if (!isPrimary() && getPerWorkingCopyInfo() == null) {
// throw newNotPresentException();
// }
//
// unitInfo = (AJCompilationUnitInfo) info;
//
// // get buffer contents
// IBuffer buffer = getBufferManager().getBuffer(AJCompilationUnit.this);
// if (buffer == null) {
// buffer = openBuffer(pm, unitInfo); // open buffer independently from the info, since we are building the info
// }
// final char[] contents = buffer == null ? null : buffer.getCharacters();
//
// // generate structure and compute syntax problems if needed
// AJCompilationUnitStructureRequestor requestor = new AJCompilationUnitStructureRequestor(this, unitInfo, newElements);
// JavaModelManager.PerWorkingCopyInfo perWorkingCopyInfo = getPerWorkingCopyInfo();
// IJavaProject project = getJavaProject();
// boolean computeProblems = JavaProject.hasJavaNature(project.getProject()) && perWorkingCopyInfo != null && perWorkingCopyInfo.isActive();
// IProblemFactory problemFactory = new DefaultProblemFactory();
// Map options = project.getOptions(true);
// AJSourceElementParser parser = new AJSourceElementParser(
// requestor,
// problemFactory,
// new CompilerOptions(options),
// true/*report local declarations*/,false);
// parser.reportOnlyOneSyntaxError = !computeProblems;
//
// //we need to set the source already here so the requestor can init
// //its jdt version of the parser (see requestor.setParser)
// parser.scanner.source = contents;
// requestor.setParser(parser);
//
// CompilationUnitDeclaration unit = parser.parseCompilationUnit(new org.aspectj.org.eclipse.jdt.internal.compiler.env.ICompilationUnit() {
// public char[] getContents() {
// return contents;
// }
// public char[] getMainTypeName() {
// return AJCompilationUnit.this.getMainTypeName();
// }
// public char[][] getPackageName() {
// return AJCompilationUnit.this.getPackageName();
// }
// public char[] getFileName() {
// return AJCompilationUnit.this.getFileName();
// }
// }, true /*full parse to find local elements*/);
//
//
// // update timestamp (might be IResource.NULL_STAMP if original does not exist)
// if (underlyingResource == null) {
// underlyingResource = getResource();
// }
// unitInfo.setTimestamp(((IFile)underlyingResource).getModificationStamp());
//
// // compute other problems if needed
// org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration compilationUnitDeclaration = null;
// try {
// if (computeProblems){
// perWorkingCopyInfo.beginReporting();
//
// AJCompilationUnitDeclarationWrapper ajcudw = new AJCompilationUnitDeclarationWrapper(unit, this);
// AJCompilationUnitStructureRequestor ajcusr = new AJCompilationUnitStructureRequestor(this, (AJCompilationUnitInfo)getElementInfo(), null);
// AJSourceElementParser2 parser2 = new AJSourceElementParser2(ajcusr, new org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory(), new org.eclipse.jdt.internal.compiler.impl.CompilerOptions(options), true,false);
//
// AjLookupEnvironment le =
// new AjLookupEnvironment(null, new CompilerOptions(options), null, null);
// unit.scope = new CompilationUnitScope(unit, le);
// compilationUnitDeclaration = AJCompilationUnitProblemFinder.process(ajcudw, this, contents, parser2, null, perWorkingCopyInfo, new org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory(), false/*don't cleanup cu*/, null);
// Map problems = new HashMap();
// compilationUnitDeclaration = AJCompilationUnitProblemFinder.process(ajcudw, parser, this.owner, problems, createAST, reconcileFlags, pm);
//
//// provisional -- only reports syntax errors
// IProblem[] problems = unit.compilationResult.problems;
// if (problems != null){
// for (int i = 0; i < problems.length; i++) {
// IProblem problem = problems[i];
// if (problem == null)
// continue;
// perWorkingCopyInfo.acceptProblem(new DefaultProblem(
// problem.getOriginatingFileName(),
// problem.getMessage(),
// problem.getID(),
// problem.getArguments(),
// problem.isError()?ProblemSeverities.Error:ProblemSeverities.Warning,
// problem.getSourceStart(),
// problem.getSourceEnd(),
// problem.getSourceLineNumber(),
// 0)); // unknown column
// }
// }
// perWorkingCopyInfo.endReporting();
//
// }
//
// if (info instanceof ASTHolderAJCUInfo && compilationUnitDeclaration != null) {
// ASTHolderAJCUInfo astHolder = (ASTHolderAJCUInfo) info;
// int astLevel = astHolder.astLevel;
// org.eclipse.jdt.core.dom.CompilationUnit cu = AST.convertCompilationUnit(astLevel, compilationUnitDeclaration, contents, options, computeProblems, (CompilationUnit)perWorkingCopyInfo.getWorkingCopy(), astHolder.reconcileFlags, pm);
// ((ASTHolderAJCUInfo) info).ast = cu;
// }
// } finally {
// if (compilationUnitDeclaration != null) {
// compilationUnitDeclaration.cleanUp();
// }
// }
// } finally {
// this.discardOriginalContentMode();
// }
//
// return unitInfo.isStructureKnown();
}
public boolean isPrimary() {
return this.owner == AJWorkingCopyOwner.INSTANCE;
}
protected Object createElementInfo() {
return new AJCompilationUnitInfo();
}
public org.eclipse.jdt.core.dom.CompilationUnit makeConsistent(int astLevel, boolean resolveBindings, int reconcileFlags, HashMap problems, IProgressMonitor monitor) throws JavaModelException {
if (isConsistent()) return null;
// create a new info and make it the current info
// (this will remove the info and its children just before storing the new infos)
if (astLevel != NO_AST || problems != null) {
ASTHolderAJCUInfo info = new ASTHolderAJCUInfo();
info.astLevel = astLevel;
info.resolveBindings = resolveBindings;
info.reconcileFlags = reconcileFlags;
info.problems = problems;
openWhenClosed(info, monitor);
org.eclipse.jdt.core.dom.CompilationUnit result = info.ast;
info.ast = null;
return result;
} else {
openWhenClosed(createElementInfo(), monitor);
return null;
}
}
/**
* @see ICompilationUnit#getWorkingCopy(WorkingCopyOwner, IProblemRequestor, IProgressMonitor)
*/
public ICompilationUnit getWorkingCopy(WorkingCopyOwner workingCopyOwner, IProblemRequestor problemRequestor, IProgressMonitor monitor) throws JavaModelException {
if (!isPrimary()) return this;
JavaModelManager manager = JavaModelManager.getJavaModelManager();
CompilationUnit workingCopy = new AJCompilationUnit((PackageFragment)getParent(), getElementName(), workingCopyOwner);
JavaModelManager.PerWorkingCopyInfo perWorkingCopyInfo =
manager.getPerWorkingCopyInfo(workingCopy, false/*don't create*/, true/*record usage*/, null/*not used since don't create*/);
if (perWorkingCopyInfo != null) {
return perWorkingCopyInfo.getWorkingCopy(); // return existing handle instead of the one created above
}
BecomeWorkingCopyOperation op = new BecomeWorkingCopyOperation(workingCopy, problemRequestor);
op.runOperation(monitor);
return workingCopy;
}
public IBuffer getBuffer() throws JavaModelException {
return convertBuffer(super.getBuffer());
}
public IBuffer convertBuffer(IBuffer buf) {
if (isInOriginalContentMode() || (buf == null))
return buf;
if (javaCompBuffer == null){
IBuffer myBuffer = BufferManager.createBuffer(this);
javaCompBuffer = new JavaCompatibleBuffer(buf, myBuffer);
} else {
if (buf != javaCompBuffer)
javaCompBuffer.reinitialize(buf);
}
return javaCompBuffer;
}
// copied from super, but changed to use an AJReconcileWorkingCopyOperation
public org.eclipse.jdt.core.dom.CompilationUnit reconcile(
int astLevel,
int reconcileFlags,
WorkingCopyOwner workingCopyOwner,
IProgressMonitor monitor)
throws JavaModelException {
if (!isWorkingCopy()) return null; // Reconciling is not supported on non working copies
if (workingCopyOwner == null) workingCopyOwner = AJWorkingCopyOwner.INSTANCE;
PerformanceStats stats = null;
if(ReconcileWorkingCopyOperation.PERF) {
stats = PerformanceStats.getStats(JavaModelManager.RECONCILE_PERF, this);
stats.startRun(new String(this.getFileName()));
}
AJReconcileWorkingCopyOperation op = new AJReconcileWorkingCopyOperation(this, astLevel, reconcileFlags, workingCopyOwner);
JavaModelManager manager = JavaModelManager.getJavaModelManager();
try {
manager.cacheZipFiles(); // cache zip files for performance (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=134172)
op.runOperation(monitor);
} finally {
manager.flushZipFiles();
}
if(ReconcileWorkingCopyOperation.PERF) {
stats.endRun();
}
return op.ast;
}
public IJavaElement[] codeSelect(int offset, int length,
WorkingCopyOwner workingCopyOwner) throws JavaModelException {
IJavaElement[] res = super.codeSelect(offset, length, workingCopyOwner);
return res;
}
protected void closeBuffer() {
if (javaCompBuffer != null){
javaCompBuffer.close();
javaCompBuffer = null;
}
super.closeBuffer();
}
private static final String moveCuUpdateCreator = "org.eclipse.jdt.internal.corext.refactoring.reorg.MoveCuUpdateCreator"; //$NON-NLS-1$
private static final int lenOfMoveCuUpdateCreator = moveCuUpdateCreator.length();
public IType[] getAllTypes() throws JavaModelException {
//tell MoveCuUpdateCreator that we do not contain any Types, otherwise it tries to find
//them using java search which will cause an ugly exception
String caller = (new RuntimeException()).getStackTrace()[1].getClassName();
if ((lenOfMoveCuUpdateCreator == caller.length()) && moveCuUpdateCreator.equals(caller))
return new IType[0];
return super.getAllTypes();
}
/**
* Hook for code completion support for AspectJ content.
*
* A description of how code completion works in AJDT can be found in bug 74419.
*
* (non-Javadoc)
* @see org.eclipse.jdt.internal.core.Openable#codeComplete(org.eclipse.jdt.internal.compiler.env.ICompilationUnit, org.eclipse.jdt.internal.compiler.env.ICompilationUnit, int, org.eclipse.jdt.core.CompletionRequestor, org.eclipse.jdt.core.WorkingCopyOwner)
*/
protected void codeComplete(
org.eclipse.jdt.internal.compiler.env.ICompilationUnit cu,
org.eclipse.jdt.internal.compiler.env.ICompilationUnit unitToSkip,
int position, CompletionRequestor requestor,
WorkingCopyOwner owner,
ITypeRoot typeRoot) throws JavaModelException {
// Bug 76146
// if we are not editing in an AspectJ editor
// (i.e., we are editing in a Java editor),
// then we do not have access to a proper parser
// and we cannot perform code completion requests.
if (!isEditingInAspectJEditor()) return;
ConversionOptions myConversionOptions; int pos;
if(javaCompBuffer == null) {
convertBuffer(super.getBuffer());
}
ConversionOptions optionsBefore = javaCompBuffer.getConversionOptions();
//check if inside intertype method declaration
char[] targetType = getITDTargetType(position);
if (targetType != null){
//we are inside an intertype method declaration -> simulate context switch to target class
myConversionOptions = ConversionOptions.getCodeCompletionOptionWithContextSwitch(position, targetType);
javaCompBuffer.setConversionOptions(myConversionOptions);
pos = javaCompBuffer.translatePositionToFake(position);
// we call codeComplete twice in this case to combine the context specific completions with the
// completions for things like local variables.
internalCodeComplete(cu, unitToSkip, pos, requestor, owner, this);
//set up proposal filter to filter away all the proposals that would be wrong because of context switch
requestor = new ProposalRequestorFilter(requestor, javaCompBuffer);
((ProposalRequestorFilter)requestor).setAcceptMemberMode(false);
} else {
requestor = new ProposalRequestorWrapper(requestor, javaCompBuffer);
}
myConversionOptions = ConversionOptions.CODE_COMPLETION;
javaCompBuffer.setConversionOptions(myConversionOptions);
pos = javaCompBuffer.translatePositionToFake(position);
internalCodeComplete(cu, unitToSkip, pos, requestor, owner, this);
javaCompBuffer.setConversionOptions(optionsBefore);
}
/**
* this method is a copy of {@link Openable#codeComplete(org.eclipse.jdt.internal.compiler.env.ICompilationUnit, org.eclipse.jdt.internal.compiler.env.ICompilationUnit, int, CompletionRequestor, WorkingCopyOwner, ITypeRoot)}
* The only change is that we need to create an {@link ITDAwareCancelableNameEnvironment}, not standard {@link SearchableEnvironment}.
*
* @param cu
* @param unitToSkip
* @param position
* @param requestor
* @param owner
* @param typeRoot
* @throws JavaModelException
*/
private void internalCodeComplete(
org.eclipse.jdt.internal.compiler.env.ICompilationUnit cu,
org.eclipse.jdt.internal.compiler.env.ICompilationUnit unitToSkip,
int position, CompletionRequestor requestor,
WorkingCopyOwner owner,
ITypeRoot typeRoot) throws JavaModelException {
if (requestor == null) {
throw new IllegalArgumentException("Completion requestor cannot be null"); //$NON-NLS-1$
}
PerformanceStats performanceStats = CompletionEngine.PERF
? PerformanceStats.getStats(JavaModelManager.COMPLETION_PERF, this)
: null;
if(performanceStats != null) {
performanceStats.startRun(new String(cu.getFileName()) + " at " + position); //$NON-NLS-1$
}
IBuffer buffer = getBuffer();
if (buffer == null) {
return;
}
if (position < -1 || position > buffer.getLength()) {
throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.INDEX_OUT_OF_BOUNDS));
}
JavaProject project = (JavaProject) getJavaProject();
ITDAwareCancelableNameEnvironment environment = new ITDAwareCancelableNameEnvironment((JavaProject) getJavaProject(), owner, null);
// set unit to skip
environment.setUnitToSkip(unitToSkip);
// code complete
CompletionEngine engine = new CompletionEngine(environment, requestor, project.getOptions(true), project, owner);
engine.complete(cu, position, 0, typeRoot);
if(performanceStats != null) {
performanceStats.endRun();
}
if (NameLookup.VERBOSE) {
AJLog.log(Thread.currentThread() + " TIME SPENT in NameLoopkup#seekTypesInSourcePackage: " + environment.nameLookup.timeSpentInSeekTypesInSourcePackage + "ms"); //$NON-NLS-1$ //$NON-NLS-2$
AJLog.log(Thread.currentThread() + " TIME SPENT in NameLoopkup#seekTypesInBinaryPackage: " + environment.nameLookup.timeSpentInSeekTypesInBinaryPackage + "ms"); //$NON-NLS-1$ //$NON-NLS-2$
}
}
/**
* As per Bug 76146
* check to see if editing in Java Editor or AspectJ editor
*/
private boolean isEditingInAspectJEditor() {
// This is a bit kludgy.
// when perWorkingCopyInfo is null
// then we are editing in Java editor
return getPerWorkingCopyInfo() != null;
}
//return null if outside intertype method declaration or the name of the target type otherwise
private char[] getITDTargetType(int pos) throws JavaModelException{
IJavaElement elt = this.getElementAt(pos);
if (elt instanceof IntertypeElement) {
IntertypeElement itd = (IntertypeElement) elt;
if (itd.getAJKind() == IProgramElement.Kind.INTER_TYPE_METHOD ||
itd.getAJKind() == IProgramElement.Kind.INTER_TYPE_CONSTRUCTOR) {
return itd.getTargetType();
}
}
return null;
}
// hack: need to use protected constructor in SourceType
private JavaElement getType(JavaElement type, String typeName) {
try {
Constructor cons = SourceType.class.getDeclaredConstructor(new Class[]{JavaElement.class,String.class});
cons.setAccessible(true);
Object obj = cons.newInstance(new Object[]{type,typeName});
return (JavaElement)obj;
} catch (SecurityException e) {
} catch (NoSuchMethodException e) {
} catch (IllegalArgumentException e) {
} catch (InstantiationException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
}
return null;
}
/*
* @see JavaElement
*/
public IJavaElement getHandleFromMemento(String token, MementoTokenizer memento, WorkingCopyOwner workingCopyOwner) {
JavaElement type = this;
if ((token.charAt(0) == JavaElement.JEM_IMPORTDECLARATION) ||
(token.charAt(0) == JavaElement.JEM_PACKAGEDECLARATION)) {
return super.getHandleFromMemento(token, memento, workingCopyOwner);
}
// need to handle types ourselves, because they may contain inner aspects
// (or inner classes containing inner aspects etc)
while ((token.charAt(0) == AspectElement.JEM_ASPECT_TYPE) ||
(token.charAt(0) == JavaElement.JEM_TYPE)) {
if (!memento.hasMoreTokens()) return type;
String typeName = memento.nextToken();
if (token.charAt(0) == AspectElement.JEM_ASPECT_TYPE) {
type = new AspectElement(type, typeName);
} else if (token.charAt(0) == JavaElement.JEM_TYPE) {
type = getType(type,typeName);
if (type == null) type = (JavaElement)getType(typeName);
}
if (!memento.hasMoreTokens()) return type;
token = memento.nextToken();
}
// handle pointcuts in a class (bug 124992)
if (!(type instanceof AspectElement)
&& (token.charAt(0) == AspectElement.JEM_POINTCUT)) {
String name = memento.nextToken();
ArrayList params = new ArrayList();
nextParam: while (memento.hasMoreTokens()) {
token = memento.nextToken();
switch (token.charAt(0)) {
case JEM_TYPE:
case JEM_TYPE_PARAMETER:
break nextParam;
case AspectElement.JEM_POINTCUT:
if (!memento.hasMoreTokens()) return this;
String param = memento.nextToken();
StringBuffer buffer = new StringBuffer();
while (param.length() == 1 && Signature.C_ARRAY == param.charAt(0)) { // backward compatible with 3.0 mementos
buffer.append(Signature.C_ARRAY);
if (!memento.hasMoreTokens()) return this;
param = memento.nextToken();
}
params.add(buffer.toString() + param);
break;
default:
break nextParam;
}
}
String[] parameters = new String[params.size()];
params.toArray(parameters);
JavaElement pointcut = new PointcutElement(type, name, parameters);
return pointcut.getHandleFromMemento(memento, workingCopyOwner);
}
return type.getHandleFromMemento(token, memento, workingCopyOwner);
}
/**
* @see JavaElement#getHandleMementoDelimiter()
*/
protected char getHandleMementoDelimiter() {
if (AspectJPlugin.usingCUprovider) {
return super.getHandleMementoDelimiter();
}
return AspectElement.JEM_ASPECT_CU;
}
public String getHandleIdentifier() {
if (AspectJPlugin.usingCUprovider) {
return super.getHandleIdentifier();
}
String callerName = (new RuntimeException()).getStackTrace()[1]
.getClassName();
final String deletionClass = "org.eclipse.jdt.internal.corext.refactoring.changes.DeleteSourceManipulationChange"; //$NON-NLS-1$
// are we being called in the context of a delete operation?
if (callerName.equals(deletionClass)) {
AJCompilationUnitManager.INSTANCE.removeFileFromModel((IFile) getResource());
// need to return a handle identifier that JDT can use (bug 74426)
String handleIdentifier = JavaCore.create(ajFile).getHandleIdentifier();
ajFile = null;
return handleIdentifier;
}
// are we being called in the context of a move/DnD operation?
final String moveClass = "org.eclipse.jdt.internal.corext.refactoring.changes.CompilationUnitReorgChange"; //$NON-NLS-1$
if (callerName.equals(moveClass)) {
// need to return a handle identifier that JDT can use (bug 121533)
String modifiedHandle = super.getHandleIdentifier().replace(
AspectElement.JEM_ASPECT_CU,
JavaElement.JEM_COMPILATIONUNIT);
return modifiedHandle;
}
return super.getHandleIdentifier();
}
/*
* Clone this handle so that it caches its contents in memory.
* DO NOT PASS TO CLIENTS
*/
public AJCompilationUnit ajCloneCachingContents() {
return new ClonedAJCU((PackageFragment) this.parent, this.name, this.owner);
}
public void setConversionOptions(ConversionOptions conversionOptions) {
javaCompBuffer.setConversionOptions(conversionOptions);
}
public ConversionOptions getConversionOptions() {
return javaCompBuffer.getConversionOptions();
}
}