X-Git-Url: http://secure.phpeclipse.com diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/SourceElementParser.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/SourceElementParser.java new file mode 100644 index 0000000..b3c72a0 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/SourceElementParser.java @@ -0,0 +1,1293 @@ +/******************************************************************************* + * Copyright (c) 2000, 2003 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package net.sourceforge.phpdt.internal.compiler; + +import java.util.ArrayList; + +import net.sourceforge.phpdt.core.compiler.CharOperation; +import net.sourceforge.phpdt.core.compiler.IProblem; +import net.sourceforge.phpdt.internal.compiler.env.ICompilationUnit; +import net.sourceforge.phpdt.internal.compiler.env.ISourceType; +import net.sourceforge.phpdt.internal.compiler.impl.ReferenceContext; +import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope; +import net.sourceforge.phpdt.internal.compiler.lookup.ClassScope; +import net.sourceforge.phpdt.internal.compiler.parser.UnitParser; +import net.sourceforge.phpdt.internal.compiler.problem.AbortCompilation; +import net.sourceforge.phpdt.internal.compiler.problem.ProblemReporter; +import net.sourceforge.phpeclipse.internal.compiler.ast.AbstractMethodDeclaration; +import net.sourceforge.phpeclipse.internal.compiler.ast.AnonymousLocalTypeDeclaration; +import net.sourceforge.phpeclipse.internal.compiler.ast.Argument; +import net.sourceforge.phpeclipse.internal.compiler.ast.AstNode; +import net.sourceforge.phpeclipse.internal.compiler.ast.CompilationUnitDeclaration; +import net.sourceforge.phpeclipse.internal.compiler.ast.ConstructorDeclaration; +import net.sourceforge.phpeclipse.internal.compiler.ast.ExplicitConstructorCall; +import net.sourceforge.phpeclipse.internal.compiler.ast.FieldDeclaration; +import net.sourceforge.phpeclipse.internal.compiler.ast.LocalTypeDeclaration; +import net.sourceforge.phpeclipse.internal.compiler.ast.MemberTypeDeclaration; +import net.sourceforge.phpeclipse.internal.compiler.ast.MethodDeclaration; +import net.sourceforge.phpeclipse.internal.compiler.ast.NameReference; +import net.sourceforge.phpeclipse.internal.compiler.ast.QualifiedAllocationExpression; +import net.sourceforge.phpeclipse.internal.compiler.ast.TypeDeclaration; +import net.sourceforge.phpeclipse.internal.compiler.ast.TypeReference; + + + +/** + * A source element parser extracts structural and reference information + * from a piece of source. + * + * also see @ISourceElementRequestor + * + * The structural investigation includes: + * - the package statement + * - import statements + * - top-level types: package member, member types (member types of member types...) + * - fields + * - methods + * + * If reference information is requested, then all source constructs are + * investigated and type, field & method references are provided as well. + * + * Any (parsing) problem encountered is also provided. + */ + +public class SourceElementParser extends UnitParser { + + ISourceElementRequestor requestor; + int fieldCount; + int localIntPtr; + int lastFieldEndPosition; + ISourceType sourceType; + boolean reportReferenceInfo; + char[][] typeNames; + char[][] superTypeNames; + int nestedTypeIndex; + static final char[] JAVA_LANG_OBJECT = "java.lang.Object".toCharArray(); //$NON-NLS-1$ + NameReference[] unknownRefs; + int unknownRefsCounter; + LocalDeclarationVisitor localDeclarationVisitor = null; +// CompilerOptions options; + +/** + * An ast visitor that visits local type declarations. + */ +public class LocalDeclarationVisitor extends AbstractSyntaxTreeVisitorAdapter { +// public boolean visit( +// AnonymousLocalTypeDeclaration anonymousTypeDeclaration, +// BlockScope scope) { +// notifySourceElementRequestor(anonymousTypeDeclaration, sourceType == null); +// return false; // don't visit members as this was done during notifySourceElementRequestor(...) +// } + public boolean visit(LocalTypeDeclaration typeDeclaration, BlockScope scope) { + notifySourceElementRequestor(typeDeclaration, sourceType == null); + return false; // don't visit members as this was done during notifySourceElementRequestor(...) + } + public boolean visit(MemberTypeDeclaration typeDeclaration, ClassScope scope) { + notifySourceElementRequestor(typeDeclaration, sourceType == null); + return false; // don't visit members as this was done during notifySourceElementRequestor(...) + } + +} + +public SourceElementParser( + final ISourceElementRequestor requestor, + IProblemFactory problemFactory) { +// CompilerOptions options) { + // we want to notify all syntax error with the acceptProblem API + // To do so, we define the record method of the ProblemReporter + super( + new ProblemReporter( + DefaultErrorHandlingPolicies.exitAfterAllProblems(), +// options, + problemFactory) { + public void record(IProblem problem, CompilationResult unitResult, ReferenceContext referenceContext) { + unitResult.record(problem, referenceContext); + requestor.acceptProblem(problem); + } + }); +// true); +// options.sourceLevel >= CompilerOptions.JDK1_4); + this.requestor = requestor; + typeNames = new char[4][]; + superTypeNames = new char[4][]; + nestedTypeIndex = 0; +// this.options = options; +} + +/** @deprecated use SourceElementParser(ISourceElementRequestor, IProblemFactory, CompilerOptions) */ +//public SourceElementParser( +// final ISourceElementRequestor requestor, +// IProblemFactory problemFactory) { +// this(requestor, problemFactory, new CompilerOptions()); +//} + +//public SourceElementParser( +// final ISourceElementRequestor requestor, +// IProblemFactory problemFactory, +// CompilerOptions options, +// boolean reportLocalDeclarations) { +// this(requestor, problemFactory, options); +// if (reportLocalDeclarations) { +// this.localDeclarationVisitor = new LocalDeclarationVisitor(); +// } +//} + +//public void checkAnnotation() { +// int firstCommentIndex = scanner.commentPtr; +// +// super.checkAnnotation(); +// +// // modify the modifier source start to point at the first comment +// if (firstCommentIndex >= 0) { +// modifiersSourceStart = scanner.commentStarts[0]; +// } +//} + +//protected void classInstanceCreation(boolean alwaysQualified) { +// +// boolean previousFlag = reportReferenceInfo; +// reportReferenceInfo = false; // not to see the type reference reported in super call to getTypeReference(...) +// super.classInstanceCreation(alwaysQualified); +// reportReferenceInfo = previousFlag; +// if (reportReferenceInfo){ +// AllocationExpression alloc = (AllocationExpression)expressionStack[expressionPtr]; +// TypeReference typeRef = alloc.type; +// requestor.acceptConstructorReference( +// typeRef instanceof SingleTypeReference +// ? ((SingleTypeReference) typeRef).token +// : CharOperation.concatWith(alloc.type.getTypeName(), '.'), +// alloc.arguments == null ? 0 : alloc.arguments.length, +// alloc.sourceStart); +// } +//} +//protected void consumeConstructorHeaderName() { +// // ConstructorHeaderName ::= Modifiersopt 'Identifier' '(' +// +// /* recovering - might be an empty message send */ +// if (currentElement != null){ +// if (lastIgnoredToken == TokenNamenew){ // was an allocation expression +// lastCheckPoint = scanner.startPosition; // force to restart at this exact position +// restartRecovery = true; +// return; +// } +// } +// SourceConstructorDeclaration cd = new SourceConstructorDeclaration(this.compilationUnit.compilationResult); +// +// //name -- this is not really revelant but we do ..... +// cd.selector = identifierStack[identifierPtr]; +// long selectorSourcePositions = identifierPositionStack[identifierPtr--]; +// identifierLengthPtr--; +// +// //modifiers +// cd.declarationSourceStart = intStack[intPtr--]; +// cd.modifiers = intStack[intPtr--]; +// +// //highlight starts at the selector starts +// cd.sourceStart = (int) (selectorSourcePositions >>> 32); +// cd.selectorSourceEnd = (int) selectorSourcePositions; +// pushOnAstStack(cd); +// +// cd.sourceEnd = lParenPos; +// cd.bodyStart = lParenPos+1; +// listLength = 0; // initialize listLength before reading parameters/throws +// +// // recovery +// if (currentElement != null){ +// lastCheckPoint = cd.bodyStart; +// if ((currentElement instanceof RecoveredType && lastIgnoredToken != TokenNameDOT) +// || cd.modifiers != 0){ +// currentElement = currentElement.add(cd, 0); +// lastIgnoredToken = -1; +// } +// } +//} +///** +// * +// * INTERNAL USE-ONLY +// */ +//protected void consumeExitVariableWithInitialization() { +// // ExitVariableWithInitialization ::= $empty +// // the scanner is located after the comma or the semi-colon. +// // we want to include the comma or the semi-colon +// super.consumeExitVariableWithInitialization(); +// if (isLocalDeclaration() || ((currentToken != TokenNameCOMMA) && (currentToken != TokenNameSEMICOLON))) +// return; +// ((SourceFieldDeclaration) astStack[astPtr]).fieldEndPosition = scanner.currentPosition - 1; +//} +//protected void consumeExitVariableWithoutInitialization() { +// // ExitVariableWithoutInitialization ::= $empty +// // do nothing by default +// super.consumeExitVariableWithoutInitialization(); +// if (isLocalDeclaration() || ((currentToken != TokenNameCOMMA) && (currentToken != TokenNameSEMICOLON))) +// return; +// ((SourceFieldDeclaration) astStack[astPtr]).fieldEndPosition = scanner.currentPosition - 1; +//} +///** +// * +// * INTERNAL USE-ONLY +// */ +//protected void consumeFieldAccess(boolean isSuperAccess) { +// // FieldAccess ::= Primary '.' 'Identifier' +// // FieldAccess ::= 'super' '.' 'Identifier' +// super.consumeFieldAccess(isSuperAccess); +// FieldReference fr = (FieldReference) expressionStack[expressionPtr]; +// if (reportReferenceInfo) { +// requestor.acceptFieldReference(fr.token, fr.sourceStart); +// } +//} +//protected void consumeMethodHeaderName() { +// // MethodHeaderName ::= Modifiersopt Type 'Identifier' '(' +// SourceMethodDeclaration md = new SourceMethodDeclaration(this.compilationUnit.compilationResult); +// +// //name +// md.selector = identifierStack[identifierPtr]; +// long selectorSourcePositions = identifierPositionStack[identifierPtr--]; +// identifierLengthPtr--; +// //type +// md.returnType = getTypeReference(intStack[intPtr--]); +// //modifiers +// md.declarationSourceStart = intStack[intPtr--]; +// md.modifiers = intStack[intPtr--]; +// +// //highlight starts at selector start +// md.sourceStart = (int) (selectorSourcePositions >>> 32); +// md.selectorSourceEnd = (int) selectorSourcePositions; +// pushOnAstStack(md); +// md.sourceEnd = lParenPos; +// md.bodyStart = lParenPos+1; +// listLength = 0; // initialize listLength before reading parameters/throws +// +// // recovery +// if (currentElement != null){ +// if (currentElement instanceof RecoveredType +// //|| md.modifiers != 0 +// || (scanner.getLineNumber(md.returnType.sourceStart) +// == scanner.getLineNumber(md.sourceStart))){ +// lastCheckPoint = md.bodyStart; +// currentElement = currentElement.add(md, 0); +// lastIgnoredToken = -1; +// } else { +// lastCheckPoint = md.sourceStart; +// restartRecovery = true; +// } +// } +//} +///** +// * +// * INTERNAL USE-ONLY +// */ +//protected void consumeMethodInvocationName() { +// // MethodInvocation ::= Name '(' ArgumentListopt ')' +// +// // when the name is only an identifier...we have a message send to "this" (implicit) +// super.consumeMethodInvocationName(); +// MessageSend messageSend = (MessageSend) expressionStack[expressionPtr]; +// Expression[] args = messageSend.arguments; +// if (reportReferenceInfo) { +// requestor.acceptMethodReference( +// messageSend.selector, +// args == null ? 0 : args.length, +// (int)(messageSend.nameSourcePosition >>> 32)); +// } +//} +///** +// * +// * INTERNAL USE-ONLY +// */ +//protected void consumeMethodInvocationPrimary() { +// super.consumeMethodInvocationPrimary(); +// MessageSend messageSend = (MessageSend) expressionStack[expressionPtr]; +// Expression[] args = messageSend.arguments; +// if (reportReferenceInfo) { +// requestor.acceptMethodReference( +// messageSend.selector, +// args == null ? 0 : args.length, +// (int)(messageSend.nameSourcePosition >>> 32)); +// } +//} +///** +// * +// * INTERNAL USE-ONLY +// */ +//protected void consumeMethodInvocationSuper() { +// // MethodInvocation ::= 'super' '.' 'Identifier' '(' ArgumentListopt ')' +// super.consumeMethodInvocationSuper(); +// MessageSend messageSend = (MessageSend) expressionStack[expressionPtr]; +// Expression[] args = messageSend.arguments; +// if (reportReferenceInfo) { +// requestor.acceptMethodReference( +// messageSend.selector, +// args == null ? 0 : args.length, +// (int)(messageSend.nameSourcePosition >>> 32)); +// } +//} +//protected void consumeSingleTypeImportDeclarationName() { +// // SingleTypeImportDeclarationName ::= 'import' Name +// /* push an ImportRef build from the last name +// stored in the identifier stack. */ +// +// super.consumeSingleTypeImportDeclarationName(); +// ImportReference impt = (ImportReference)astStack[astPtr]; +// if (reportReferenceInfo) { +// requestor.acceptTypeReference(impt.tokens, impt.sourceStart, impt.sourceEnd); +// } +//} +//protected void consumeTypeImportOnDemandDeclarationName() { +// // TypeImportOnDemandDeclarationName ::= 'import' Name '.' '*' +// /* push an ImportRef build from the last name +// stored in the identifier stack. */ +// +// super.consumeTypeImportOnDemandDeclarationName(); +// ImportReference impt = (ImportReference)astStack[astPtr]; +// if (reportReferenceInfo) { +// requestor.acceptUnknownReference(impt.tokens, impt.sourceStart, impt.sourceEnd); +// } +//} +//protected FieldDeclaration createFieldDeclaration(Expression initialization, char[] name, int sourceStart, int sourceEnd) { +// return new SourceFieldDeclaration(null, name, sourceStart, sourceEnd); +//} +//protected CompilationUnitDeclaration endParse(int act) { +// if (sourceType != null) { +// if (sourceType.isInterface()) { +// consumeInterfaceDeclaration(); +// } else { +// consumeClassDeclaration(); +// } +// } +// if (compilationUnit != null) { +// CompilationUnitDeclaration result = super.endParse(act); +// return result; +// } else { +// return null; +// } +//} +/* + * Flush annotations defined prior to a given positions. + * + * Note: annotations are stacked in syntactical order + * + * Either answer given , or the end position of a comment line + * immediately following the (same line) + * + * e.g. + * void foo(){ + * } // end of method foo + */ +// +//public int flushAnnotationsDefinedPriorTo(int position) { +// +// return lastFieldEndPosition = super.flushAnnotationsDefinedPriorTo(position); +//} +//public TypeReference getTypeReference(int dim) { +// /* build a Reference on a variable that may be qualified or not +// * This variable is a type reference and dim will be its dimensions +// */ +// int length; +// if ((length = identifierLengthStack[identifierLengthPtr--]) == 1) { +// // single variable reference +// if (dim == 0) { +// SingleTypeReference ref = +// new SingleTypeReference( +// identifierStack[identifierPtr], +// identifierPositionStack[identifierPtr--]); +// if (reportReferenceInfo) { +// requestor.acceptTypeReference(ref.token, ref.sourceStart); +// } +// return ref; +// } else { +// ArrayTypeReference ref = +// new ArrayTypeReference( +// identifierStack[identifierPtr], +// dim, +// identifierPositionStack[identifierPtr--]); +// ref.sourceEnd = endPosition; +// if (reportReferenceInfo) { +// requestor.acceptTypeReference(ref.token, ref.sourceStart); +// } +// return ref; +// } +// } else { +// if (length < 0) { //flag for precompiled type reference on base types +// TypeReference ref = TypeReference.baseTypeReference(-length, dim); +// ref.sourceStart = intStack[intPtr--]; +// if (dim == 0) { +// ref.sourceEnd = intStack[intPtr--]; +// } else { +// intPtr--; // no need to use this position as it is an array +// ref.sourceEnd = endPosition; +// } +// if (reportReferenceInfo){ +// requestor.acceptTypeReference(ref.getTypeName(), ref.sourceStart, ref.sourceEnd); +// } +// return ref; +// } else { //Qualified variable reference +// char[][] tokens = new char[length][]; +// identifierPtr -= length; +// long[] positions = new long[length]; +// System.arraycopy(identifierStack, identifierPtr + 1, tokens, 0, length); +// System.arraycopy( +// identifierPositionStack, +// identifierPtr + 1, +// positions, +// 0, +// length); +// if (dim == 0) { +// QualifiedTypeReference ref = new QualifiedTypeReference(tokens, positions); +// if (reportReferenceInfo) { +// requestor.acceptTypeReference(ref.tokens, ref.sourceStart, ref.sourceEnd); +// } +// return ref; +// } else { +// ArrayQualifiedTypeReference ref = +// new ArrayQualifiedTypeReference(tokens, dim, positions); +// ref.sourceEnd = endPosition; +// if (reportReferenceInfo) { +// requestor.acceptTypeReference(ref.tokens, ref.sourceStart, ref.sourceEnd); +// } +// return ref; +// } +// } +// } +//} +//public NameReference getUnspecifiedReference() { +// /* build a (unspecified) NameReference which may be qualified*/ +// +// int length; +// if ((length = identifierLengthStack[identifierLengthPtr--]) == 1) { +// // single variable reference +// SingleNameReference ref = +// new SingleNameReference( +// identifierStack[identifierPtr], +// identifierPositionStack[identifierPtr--]); +// if (reportReferenceInfo) { +// this.addUnknownRef(ref); +// } +// return ref; +// } else { +// //Qualified variable reference +// char[][] tokens = new char[length][]; +// identifierPtr -= length; +// System.arraycopy(identifierStack, identifierPtr + 1, tokens, 0, length); +// QualifiedNameReference ref = +// new QualifiedNameReference( +// tokens, +// (int) (identifierPositionStack[identifierPtr + 1] >> 32), // sourceStart +// (int) identifierPositionStack[identifierPtr + length]); // sourceEnd +// if (reportReferenceInfo) { +// this.addUnknownRef(ref); +// } +// return ref; +// } +//} +//public NameReference getUnspecifiedReferenceOptimized() { +// /* build a (unspecified) NameReference which may be qualified +// The optimization occurs for qualified reference while we are +// certain in this case the last item of the qualified name is +// a field access. This optimization is IMPORTANT while it results +// that when a NameReference is build, the type checker should always +// look for that it is not a type reference */ +// +// int length; +// if ((length = identifierLengthStack[identifierLengthPtr--]) == 1) { +// // single variable reference +// SingleNameReference ref = +// new SingleNameReference( +// identifierStack[identifierPtr], +// identifierPositionStack[identifierPtr--]); +// ref.bits &= ~AstNode.RestrictiveFlagMASK; +// ref.bits |= LOCAL | FIELD; +// if (reportReferenceInfo) { +// this.addUnknownRef(ref); +// } +// return ref; +// } +// +// //Qualified-variable-reference +// //In fact it is variable-reference DOT field-ref , but it would result in a type +// //conflict tha can be only reduce by making a superclass (or inetrface ) between +// //nameReference and FiledReference or putting FieldReference under NameReference +// //or else..........This optimisation is not really relevant so just leave as it is +// +// char[][] tokens = new char[length][]; +// identifierPtr -= length; +// System.arraycopy(identifierStack, identifierPtr + 1, tokens, 0, length); +// QualifiedNameReference ref = +// new QualifiedNameReference( +// tokens, +// (int) (identifierPositionStack[identifierPtr + 1] >> 32), +// // sourceStart +// (int) identifierPositionStack[identifierPtr + length]); // sourceEnd +// ref.bits &= ~AstNode.RestrictiveFlagMASK; +// ref.bits |= LOCAL | FIELD; +// if (reportReferenceInfo) { +// this.addUnknownRef(ref); +// } +// return ref; +//} +///** +// * +// * INTERNAL USE-ONLY +// */ +//private boolean isLocalDeclaration() { +// int nestedDepth = nestedType; +// while (nestedDepth >= 0) { +// if (nestedMethod[nestedDepth] != 0) { +// return true; +// } +// nestedDepth--; +// } +// return false; +//} +/* + * Update the bodyStart of the corresponding parse node + */ +public void notifySourceElementRequestor(CompilationUnitDeclaration parsedUnit) { + if (parsedUnit == null) { + // when we parse a single type member declaration the compilation unit is null, but we still + // want to be able to notify the requestor on the created ast node + if (astStack[0] instanceof AbstractMethodDeclaration) { + notifySourceElementRequestor((AbstractMethodDeclaration) astStack[0]); + return; + } + return; + } + // range check + boolean isInRange = + scanner.initialPosition <= parsedUnit.sourceStart + && scanner.eofPosition >= parsedUnit.sourceEnd; + +// if (reportReferenceInfo) { +// notifyAllUnknownReferences(); +// } + // collect the top level ast nodes + int length = 0; + AstNode[] nodes = null; + if (sourceType == null){ + if (isInRange) { + requestor.enterCompilationUnit(); + } +// ImportReference currentPackage = parsedUnit.currentPackage; +// ImportReference[] imports = parsedUnit.imports; +// TypeDeclaration[] types = parsedUnit.types; + ArrayList types = parsedUnit.types; + if (types != null) { +// length = +// (currentPackage == null ? 0 : 1) +// + (imports == null ? 0 : imports.length) +// + (types == null ? 0 : types.length); +// nodes = new AstNode[length]; + length = types.size(); + nodes = new AstNode[length]; + int index = 0; +// if (currentPackage != null) { +// nodes[index++] = currentPackage; +// } +// if (imports != null) { +// for (int i = 0, max = imports.length; i < max; i++) { +// nodes[index++] = imports[i]; +// } +// } + + for (int i = 0, max = types.size(); i < max; i++) { + nodes[index++] = (AstNode)types.get(i); + } + } + } else { +// TypeDeclaration[] types = parsedUnit.types; + ArrayList types = parsedUnit.types; + if (types != null) { + length = types.size(); + nodes = new AstNode[length]; + for (int i = 0, max = types.size(); i < max; i++) { + nodes[i] = (AstNode)types.get(i); + } + } + } + + // notify the nodes in the syntactical order + if (nodes != null && length > 0) { + quickSort(nodes, 0, length-1); + for (int i=0;i= methodDeclaration.declarationSourceEnd; + + if (methodDeclaration.isClinit()) { + this.visitIfNeeded(methodDeclaration); + return; + } + + if (methodDeclaration.isDefaultConstructor()) { + if (reportReferenceInfo) { + ConstructorDeclaration constructorDeclaration = (ConstructorDeclaration) methodDeclaration; + ExplicitConstructorCall constructorCall = constructorDeclaration.constructorCall; + if (constructorCall != null) { + switch(constructorCall.accessMode) { + case ExplicitConstructorCall.This : + requestor.acceptConstructorReference( + typeNames[nestedTypeIndex-1], + constructorCall.arguments == null ? 0 : constructorCall.arguments.length, + constructorCall.sourceStart); + break; + case ExplicitConstructorCall.Super : + case ExplicitConstructorCall.ImplicitSuper : + requestor.acceptConstructorReference( + superTypeNames[nestedTypeIndex-1], + constructorCall.arguments == null ? 0 : constructorCall.arguments.length, + constructorCall.sourceStart); + break; + } + } + } + return; + } + char[][] argumentTypes = null; + char[][] argumentNames = null; + Argument[] arguments = methodDeclaration.arguments; + if (arguments != null) { + int argumentLength = arguments.length; + argumentTypes = new char[argumentLength][]; + argumentNames = new char[argumentLength][]; + for (int i = 0; i < argumentLength; i++) { + argumentTypes[i] = returnTypeName(arguments[i].type); + argumentNames[i] = arguments[i].name; + } + } + char[][] thrownExceptionTypes = null; + TypeReference[] thrownExceptions = methodDeclaration.thrownExceptions; + if (thrownExceptions != null) { + int thrownExceptionLength = thrownExceptions.length; + thrownExceptionTypes = new char[thrownExceptionLength][]; + for (int i = 0; i < thrownExceptionLength; i++) { + thrownExceptionTypes[i] = + CharOperation.concatWith(thrownExceptions[i].getTypeName(), '.'); + } + } + // by default no selector end position + int selectorSourceEnd = -1; + if (methodDeclaration.isConstructor()) { +// if (methodDeclaration instanceof SourceConstructorDeclaration) { +// selectorSourceEnd = +// ((SourceConstructorDeclaration) methodDeclaration).selectorSourceEnd; +// } + if (isInRange){ + requestor.enterConstructor( + methodDeclaration.declarationSourceStart, + methodDeclaration.modifiers, + methodDeclaration.selector, + methodDeclaration.sourceStart, + selectorSourceEnd, + argumentTypes, + argumentNames, + thrownExceptionTypes); + } + if (reportReferenceInfo) { + ConstructorDeclaration constructorDeclaration = (ConstructorDeclaration) methodDeclaration; + ExplicitConstructorCall constructorCall = constructorDeclaration.constructorCall; + if (constructorCall != null) { + switch(constructorCall.accessMode) { + case ExplicitConstructorCall.This : + requestor.acceptConstructorReference( + typeNames[nestedTypeIndex-1], + constructorCall.arguments == null ? 0 : constructorCall.arguments.length, + constructorCall.sourceStart); + break; + case ExplicitConstructorCall.Super : + case ExplicitConstructorCall.ImplicitSuper : + requestor.acceptConstructorReference( + superTypeNames[nestedTypeIndex-1], + constructorCall.arguments == null ? 0 : constructorCall.arguments.length, + constructorCall.sourceStart); + break; + } + } + } + this.visitIfNeeded(methodDeclaration); + if (isInRange){ + requestor.exitConstructor(methodDeclaration.declarationSourceEnd); + } + return; + } +// if (methodDeclaration instanceof SourceMethodDeclaration) { +// selectorSourceEnd = +// ((SourceMethodDeclaration) methodDeclaration).selectorSourceEnd; +// } + if (isInRange) { + int modifiers = methodDeclaration.modifiers; +// boolean deprecated = (modifiers & AccDeprecated) != 0; // remember deprecation so as to not lose it below + requestor.enterMethod( + methodDeclaration.declarationSourceStart, + modifiers, // deprecated ? (modifiers & AccJustFlag) | AccDeprecated : modifiers & AccJustFlag, + returnTypeName(((MethodDeclaration) methodDeclaration).returnType), + methodDeclaration.selector, + methodDeclaration.sourceStart, + selectorSourceEnd, + argumentTypes, + argumentNames, + thrownExceptionTypes); + } + this.visitIfNeeded(methodDeclaration); + + if (isInRange){ + requestor.exitMethod(methodDeclaration.declarationSourceEnd); + } +} +///* +//* Update the bodyStart of the corresponding parse node +//*/ +//public void notifySourceElementRequestor(FieldDeclaration fieldDeclaration) { +// +// // range check +// boolean isInRange = +// scanner.initialPosition <= fieldDeclaration.declarationSourceStart +// && scanner.eofPosition >= fieldDeclaration.declarationSourceEnd; +// +// if (fieldDeclaration.isField()) { +// int fieldEndPosition = fieldDeclaration.declarationSourceEnd; +// if (fieldDeclaration instanceof SourceFieldDeclaration) { +// fieldEndPosition = ((SourceFieldDeclaration) fieldDeclaration).fieldEndPosition; +// if (fieldEndPosition == 0) { +// // use the declaration source end by default +// fieldEndPosition = fieldDeclaration.declarationSourceEnd; +// } +// } +// if (isInRange) { +// int modifiers = fieldDeclaration.modifiers; +// boolean deprecated = (modifiers & AccDeprecated) != 0; // remember deprecation so as to not lose it below +// requestor.enterField( +// fieldDeclaration.declarationSourceStart, +// deprecated ? (modifiers & AccJustFlag) | AccDeprecated : modifiers & AccJustFlag, +// returnTypeName(fieldDeclaration.type), +// fieldDeclaration.name, +// fieldDeclaration.sourceStart, +// fieldDeclaration.sourceEnd); +// } +// this.visitIfNeeded(fieldDeclaration); +// if (isInRange){ +// requestor.exitField( +// // filter out initializations that are not a constant (simple check) +// (fieldDeclaration.initialization == null +// || fieldDeclaration.initialization instanceof ArrayInitializer +// || fieldDeclaration.initialization instanceof AllocationExpression +// || fieldDeclaration.initialization instanceof ArrayAllocationExpression +// || fieldDeclaration.initialization instanceof Assignment +// || fieldDeclaration.initialization instanceof ClassLiteralAccess +// || fieldDeclaration.initialization instanceof MessageSend +// || fieldDeclaration.initialization instanceof ArrayReference +// || fieldDeclaration.initialization instanceof ThisReference) ? +// -1 : +// fieldDeclaration.initialization.sourceStart, +// fieldEndPosition, +// fieldDeclaration.declarationSourceEnd); +// } +// +// } else { +// if (isInRange){ +// requestor.enterInitializer( +// fieldDeclaration.declarationSourceStart, +// fieldDeclaration.modifiers); +// } +// this.visitIfNeeded((Initializer)fieldDeclaration); +// if (isInRange){ +// requestor.exitInitializer(fieldDeclaration.declarationSourceEnd); +// } +// } +//} +//public void notifySourceElementRequestor( +// ImportReference importReference, +// boolean isPackage) { +// if (isPackage) { +// requestor.acceptPackage( +// importReference.declarationSourceStart, +// importReference.declarationSourceEnd, +// CharOperation.concatWith(importReference.getImportName(), '.')); +// } else { +// requestor.acceptImport( +// importReference.declarationSourceStart, +// importReference.declarationSourceEnd, +// CharOperation.concatWith(importReference.getImportName(), '.'), +// importReference.onDemand); +// } +//} +public void notifySourceElementRequestor(TypeDeclaration typeDeclaration, boolean notifyTypePresence) { +//// public void notifySourceElementRequestor(AstNode typeDeclaration, boolean notifyTypePresence) { + + // range check + boolean isInRange = + scanner.initialPosition <= typeDeclaration.declarationSourceStart + && scanner.eofPosition >= typeDeclaration.declarationSourceEnd; + + FieldDeclaration[] fields = typeDeclaration.fields; + AbstractMethodDeclaration[] methods = typeDeclaration.methods; + MemberTypeDeclaration[] memberTypes = typeDeclaration.memberTypes; + int fieldCount = fields == null ? 0 : fields.length; + int methodCount = methods == null ? 0 : methods.length; + int memberTypeCount = memberTypes == null ? 0 : memberTypes.length; + int fieldIndex = 0; + int methodIndex = 0; + int memberTypeIndex = 0; + boolean isInterface = typeDeclaration.isInterface(); + + if (notifyTypePresence){ + char[][] interfaceNames = null; + int superInterfacesLength = 0; + TypeReference[] superInterfaces = typeDeclaration.superInterfaces; + if (superInterfaces != null) { + superInterfacesLength = superInterfaces.length; + interfaceNames = new char[superInterfacesLength][]; + } else { + if (typeDeclaration instanceof AnonymousLocalTypeDeclaration) { + // see PR 3442 + QualifiedAllocationExpression alloc = ((AnonymousLocalTypeDeclaration)typeDeclaration).allocation; + if (alloc != null && alloc.type != null) { + superInterfaces = new TypeReference[] { ((AnonymousLocalTypeDeclaration)typeDeclaration).allocation.type}; + superInterfacesLength = 1; + interfaceNames = new char[1][]; + } + } + } + if (superInterfaces != null) { + for (int i = 0; i < superInterfacesLength; i++) { + interfaceNames[i] = + CharOperation.concatWith(superInterfaces[i].getTypeName(), '.'); + } + } + if (isInterface) { + if (isInRange){ + int modifiers = typeDeclaration.modifiers; + boolean deprecated = false; //(modifiers & AccDeprecated) != 0; // remember deprecation so as to not lose it below + requestor.enterInterface( + typeDeclaration.declarationSourceStart, + modifiers, //deprecated ? (modifiers & AccJustFlag) | AccDeprecated : modifiers & AccJustFlag, + typeDeclaration.name, + typeDeclaration.sourceStart, + typeDeclaration.sourceEnd, + interfaceNames); + } + if (nestedTypeIndex == typeNames.length) { + // need a resize + System.arraycopy(typeNames, 0, (typeNames = new char[nestedTypeIndex * 2][]), 0, nestedTypeIndex); + System.arraycopy(superTypeNames, 0, (superTypeNames = new char[nestedTypeIndex * 2][]), 0, nestedTypeIndex); + } + typeNames[nestedTypeIndex] = typeDeclaration.name; + superTypeNames[nestedTypeIndex++] = JAVA_LANG_OBJECT; + } else { + TypeReference superclass = typeDeclaration.superclass; + if (superclass == null) { + if (isInRange){ + requestor.enterClass( + typeDeclaration.declarationSourceStart, + typeDeclaration.modifiers, + typeDeclaration.name, + typeDeclaration.sourceStart, + typeDeclaration.sourceEnd, + null, + interfaceNames); + } + } else { + if (isInRange){ + requestor.enterClass( + typeDeclaration.declarationSourceStart, + typeDeclaration.modifiers, + typeDeclaration.name, + typeDeclaration.sourceStart, + typeDeclaration.sourceEnd, + CharOperation.concatWith(superclass.getTypeName(), '.'), + interfaceNames); + } + } + if (nestedTypeIndex == typeNames.length) { + // need a resize + System.arraycopy(typeNames, 0, (typeNames = new char[nestedTypeIndex * 2][]), 0, nestedTypeIndex); + System.arraycopy(superTypeNames, 0, (superTypeNames = new char[nestedTypeIndex * 2][]), 0, nestedTypeIndex); + } + typeNames[nestedTypeIndex] = typeDeclaration.name; + superTypeNames[nestedTypeIndex++] = superclass == null ? JAVA_LANG_OBJECT : CharOperation.concatWith(superclass.getTypeName(), '.'); + } + } + while ((fieldIndex < fieldCount) + || (memberTypeIndex < memberTypeCount) + || (methodIndex < methodCount)) { + FieldDeclaration nextFieldDeclaration = null; + AbstractMethodDeclaration nextMethodDeclaration = null; + TypeDeclaration nextMemberDeclaration = null; + + int position = Integer.MAX_VALUE; + int nextDeclarationType = -1; + if (fieldIndex < fieldCount) { + nextFieldDeclaration = fields[fieldIndex]; + if (nextFieldDeclaration.declarationSourceStart < position) { + position = nextFieldDeclaration.declarationSourceStart; + nextDeclarationType = 0; // FIELD + } + } + if (methodIndex < methodCount) { + nextMethodDeclaration = methods[methodIndex]; + if (nextMethodDeclaration.declarationSourceStart < position) { + position = nextMethodDeclaration.declarationSourceStart; + nextDeclarationType = 1; // METHOD + } + } + if (memberTypeIndex < memberTypeCount) { + nextMemberDeclaration = memberTypes[memberTypeIndex]; + if (nextMemberDeclaration.declarationSourceStart < position) { + position = nextMemberDeclaration.declarationSourceStart; + nextDeclarationType = 2; // MEMBER + } + } + switch (nextDeclarationType) { + case 0 : + fieldIndex++; +// notifySourceElementRequestor(nextFieldDeclaration); + break; + case 1 : + methodIndex++; + notifySourceElementRequestor(nextMethodDeclaration); + break; + case 2 : + memberTypeIndex++; + notifySourceElementRequestor(nextMemberDeclaration, true); + } + } + if (notifyTypePresence){ + if (isInRange){ + if (isInterface) { + requestor.exitInterface(typeDeclaration.declarationSourceEnd); + } else { + requestor.exitClass(typeDeclaration.declarationSourceEnd); + } + } + nestedTypeIndex--; + } +} +public void parseCompilationUnit ( + ICompilationUnit unit, + int start, + int end ) { +// boolean needReferenceInfo) { + +// reportReferenceInfo = needReferenceInfo; +// boolean old = diet; +// if (needReferenceInfo) { +// unknownRefs = new NameReference[10]; +// unknownRefsCounter = 0; +// } + + try { +// diet = true; + CompilationResult compilationUnitResult = new CompilationResult(unit, 0, 0, 10); //this.options.maxProblemsPerUnit); + CompilationUnitDeclaration parsedUnit = parse(unit, compilationUnitResult, start, end); +// if (scanner.recordLineSeparator) { +// requestor.acceptLineSeparatorPositions(scanner.getLineEnds()); +// } +// if (this.localDeclarationVisitor != null || needReferenceInfo){ +// diet = false; +// this.getMethodBodies(parsedUnit); +// } +// this.scanner.resetTo(start, end); +// notifySourceElementRequestor(parsedUnit); + } catch (AbortCompilation e) { + } finally { +// diet = old; + } +} +public void parseCompilationUnit( + ICompilationUnit unit, + boolean needReferenceInfo) { +// boolean old = diet; +// if (needReferenceInfo) { +// unknownRefs = new NameReference[10]; +// unknownRefsCounter = 0; +// } + + try { +// diet = true; + reportReferenceInfo = needReferenceInfo; + CompilationResult compilationUnitResult = new CompilationResult(unit, 0, 0, 10); //this.options.maxProblemsPerUnit); + CompilationUnitDeclaration parsedUnit = parse(unit, compilationUnitResult); + if (scanner.recordLineSeparator) { + requestor.acceptLineSeparatorPositions(scanner.getLineEnds()); + } + int initialStart = this.scanner.initialPosition; + int initialEnd = this.scanner.eofPosition; +// if (this.localDeclarationVisitor != null || needReferenceInfo){ +// diet = false; +// this.getMethodBodies(parsedUnit); +// } + this.scanner.resetTo(initialStart, initialEnd); + notifySourceElementRequestor(parsedUnit); + } catch (AbortCompilation e) { + } finally { +// diet = old; + } +} +//public void parseTypeMemberDeclarations( +// ISourceType sourceType, +// ICompilationUnit sourceUnit, +// int start, +// int end, +// boolean needReferenceInfo) { +// boolean old = diet; +// if (needReferenceInfo) { +// unknownRefs = new NameReference[10]; +// unknownRefsCounter = 0; +// } +// +// try { +// diet = !needReferenceInfo; +// reportReferenceInfo = needReferenceInfo; +// CompilationResult compilationUnitResult = +// new CompilationResult(sourceUnit, 0, 0, this.options.maxProblemsPerUnit); +// CompilationUnitDeclaration unit = +// SourceTypeConverter.buildCompilationUnit( +// new ISourceType[]{sourceType}, +// false, // no need for field and methods +// false, // no need for member types +// false, // no need for field initialization +// problemReporter(), +// compilationUnitResult); +// if ((unit == null) || (unit.types == null) || (unit.types.length != 1)) +// return; +// this.sourceType = sourceType; +// try { +// /* automaton initialization */ +// initialize(); +// goForClassBodyDeclarations(); +// /* scanner initialization */ +// scanner.setSource(sourceUnit.getContents()); +// scanner.resetTo(start, end); +// /* unit creation */ +// referenceContext = compilationUnit = unit; +// /* initialize the astStacl */ +// // the compilationUnitDeclaration should contain exactly one type +// pushOnAstStack(unit.types[0]); +// /* run automaton */ +// parse(); +// notifySourceElementRequestor(unit); +// } finally { +// unit = compilationUnit; +// compilationUnit = null; // reset parser +// } +// } catch (AbortCompilation e) { +// } finally { +// if (scanner.recordLineSeparator) { +// requestor.acceptLineSeparatorPositions(scanner.getLineEnds()); +// } +// diet = old; +// } +//} +// +//public void parseTypeMemberDeclarations( +// char[] contents, +// int start, +// int end) { +// +// boolean old = diet; +// +// try { +// diet = true; +// +// /* automaton initialization */ +// initialize(); +// goForClassBodyDeclarations(); +// /* scanner initialization */ +// scanner.setSource(contents); +// scanner.recordLineSeparator = false; +// scanner.taskTags = null; +// scanner.taskPriorities = null; +// scanner.resetTo(start, end); +// +// /* unit creation */ +// referenceContext = null; +// +// /* initialize the astStacl */ +// // the compilationUnitDeclaration should contain exactly one type +// /* run automaton */ +// parse(); +// notifySourceElementRequestor((CompilationUnitDeclaration)null); +// } catch (AbortCompilation e) { +// } finally { +// diet = old; +// } +//} +/** + * Sort the given ast nodes by their positions. + */ +private static void quickSort(AstNode[] sortedCollection, int left, int right) { + int original_left = left; + int original_right = right; + AstNode mid = sortedCollection[ (left + right) / 2]; + do { + while (sortedCollection[left].sourceStart < mid.sourceStart) { + left++; + } + while (mid.sourceStart < sortedCollection[right].sourceStart) { + right--; + } + if (left <= right) { + AstNode tmp = sortedCollection[left]; + sortedCollection[left] = sortedCollection[right]; + sortedCollection[right] = tmp; + left++; + right--; + } + } while (left <= right); + if (original_left < right) { + quickSort(sortedCollection, original_left, right); + } + if (left < original_right) { + quickSort(sortedCollection, left, original_right); + } +} +/* + * Answer a char array representation of the type name formatted like: + * - type name + dimensions + * Example: + * "A[][]".toCharArray() + * "java.lang.String".toCharArray() + */ +private char[] returnTypeName(TypeReference type) { + if (type == null) + return null; + int dimension = type.dimensions(); + if (dimension != 0) { + char[] dimensionsArray = new char[dimension * 2]; + for (int i = 0; i < dimension; i++) { + dimensionsArray[i * 2] = '['; + dimensionsArray[(i * 2) + 1] = ']'; + } + return CharOperation.concat( + CharOperation.concatWith(type.getTypeName(), '.'), + dimensionsArray); + } + return CharOperation.concatWith(type.getTypeName(), '.'); +} + +public void addUnknownRef(NameReference nameRef) { + if (this.unknownRefs.length == this.unknownRefsCounter) { + // resize + System.arraycopy( + this.unknownRefs, + 0, + (this.unknownRefs = new NameReference[this.unknownRefsCounter * 2]), + 0, + this.unknownRefsCounter); + } + this.unknownRefs[this.unknownRefsCounter++] = nameRef; +} + +private void visitIfNeeded(AbstractMethodDeclaration method) { + if (this.localDeclarationVisitor != null + && (method.bits & AstNode.HasLocalTypeMASK) != 0) { + if (method.statements != null) { + int statementsLength = method.statements.length; + for (int i = 0; i < statementsLength; i++) + method.statements[i].traverse(this.localDeclarationVisitor, method.scope); + } + } +} + +//private void visitIfNeeded(FieldDeclaration field) { +// if (this.localDeclarationVisitor != null +// && (field.bits & AstNode.HasLocalTypeMASK) != 0) { +// if (field.initialization != null) { +// field.initialization.traverse(this.localDeclarationVisitor, null); +// } +// } +//} +// +//private void visitIfNeeded(Initializer initializer) { +// if (this.localDeclarationVisitor != null +// && (initializer.bits & AstNode.HasLocalTypeMASK) != 0) { +// if (initializer.block != null) { +// initializer.block.traverse(this.localDeclarationVisitor, null); +// } +// } +//} +// +//protected void reportSyntaxError(int act, int currentKind, int stateStackTop) { +// if (compilationUnit == null) return; +// super.reportSyntaxError(act, currentKind,stateStackTop); +//} + +}