diff options
author | Stephan Herrmann | 2010-04-01 19:56:59 +0000 |
---|---|---|
committer | Stephan Herrmann | 2010-04-01 19:56:59 +0000 |
commit | 7b7062f3b12bba7ef33116efb94da1f54e069625 (patch) | |
tree | 953104b5ab329138aac4d340fb014e321cd658a2 /org.eclipse.jdt.core/dom/org/eclipse | |
parent | b41f944c832b588bb998e321bf7fd9a4e1c62c08 (diff) | |
download | org.eclipse.objectteams-7b7062f3b12bba7ef33116efb94da1f54e069625.tar.gz org.eclipse.objectteams-7b7062f3b12bba7ef33116efb94da1f54e069625.tar.xz org.eclipse.objectteams-7b7062f3b12bba7ef33116efb94da1f54e069625.zip |
initial commit in accordance with CQ 3784
Diffstat (limited to 'org.eclipse.jdt.core/dom/org/eclipse')
178 files changed, 84307 insertions, 0 deletions
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AST.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AST.java new file mode 100644 index 000000000..d834924a5 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AST.java @@ -0,0 +1,3154 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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 + * $Id: AST.java 22567 2009-09-22 16:34:06Z stephan $ + * + * Contributors: + * IBM Corporation - initial API and implementation + * Fraunhofer FIRST - extended API and implementation + * Technical University Berlin - extended API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; + +import org.eclipse.core.runtime.IProgressMonitor; + +import org.eclipse.jdt.core.IClassFile; +import org.eclipse.jdt.core.ICompilationUnit; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.dom.Modifier.ModifierKeyword; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; +import org.eclipse.jdt.internal.compiler.parser.Scanner; +import org.eclipse.jface.text.IDocument; +import org.eclipse.text.edits.TextEdit; + +/** + * Umbrella owner and abstract syntax tree node factory. + * An <code>AST</code> instance serves as the common owner of any number of + * AST nodes, and as the factory for creating new AST nodes owned by that + * instance. + * <p> + * Abstract syntax trees may be hand constructed by clients, using the + * <code>new<i>TYPE</i></code> factory methods to create new nodes, and the + * various <code>set<i>CHILD</i></code> methods + * (see {@link org.eclipse.jdt.core.dom.ASTNode ASTNode} and its subclasses) + * to connect them together. + * </p> + * <p> + * Each AST node belongs to a unique AST instance, called the owning AST. + * The children of an AST node always have the same owner as their parent node. + * If a node from one AST is to be added to a different AST, the subtree must + * be cloned first to ensures that the added nodes have the correct owning AST. + * </p> + * <p> + * There can be any number of AST nodes owned by a single AST instance that are + * unparented. Each of these nodes is the root of a separate little tree of nodes. + * The method <code>ASTNode.getRoot()</code> navigates from any node to the root + * of the tree that it is contained in. Ordinarily, an AST instance has one main + * tree (rooted at a <code>CompilationUnit</code>), with newly-created nodes appearing + * as additional roots until they are parented somewhere under the main tree. + * One can navigate from any node to its AST instance, but not conversely. + * </p> + * <p> + * The class {@link ASTParser} parses a string + * containing a Java source code and returns an abstract syntax tree + * for it. The resulting nodes carry source ranges relating the node back to + * the original source characters. + * </p> + * <p> + * Compilation units created by <code>ASTParser</code> from a + * source document can be serialized after arbitrary modifications + * with minimal loss of original formatting. Here is an example: + * <pre> + * Document doc = new Document("import java.util.List;\nclass X {}\n"); + * ASTParser parser = ASTParser.newParser(AST.JLS3); + * parser.setSource(doc.get().toCharArray()); + * CompilationUnit cu = (CompilationUnit) parser.createAST(null); + * cu.recordModifications(); + * AST ast = cu.getAST(); + * ImportDeclaration id = ast.newImportDeclaration(); + * id.setName(ast.newName(new String[] {"java", "util", "Set"}); + * cu.imports().add(id); // add import declaration at end + * TextEdit edits = cu.rewrite(document, null); + * UndoEdit undo = edits.apply(document); + * </pre> + * See also {@link org.eclipse.jdt.core.dom.rewrite.ASTRewrite} for + * an alternative way to describe and serialize changes to a + * read-only AST. + * </p> + * <p> + * Clients may create instances of this class using {@link #newAST(int)}, + * but this class is not intended to be subclassed. + * </p> + * + * @see ASTParser + * @see ASTNode + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +@SuppressWarnings("unchecked") +public final class AST { + /** + * Constant for indicating the AST API that handles JLS2. + * This API is capable of handling all constructs + * in the Java language as described in the Java Language + * Specification, Second Edition (JLS2). + * JLS2 is a superset of all earlier versions of the + * Java language, and the JLS2 API can be used to manipulate + * programs written in all versions of the Java language + * up to and including J2SE 1.4. + * + * @since 3.0 + * @deprecated Clients should use the {@link #JLS3} AST API instead. + */ + public static final int JLS2 = 2; + + /** + * Internal synonym for {@link #JLS2}. Use to alleviate + * deprecation warnings. + * @since 3.1 + */ + /*package*/ static final int JLS2_INTERNAL = JLS2; + + /** + * Constant for indicating the AST API that handles JLS3. + * This API is capable of handling all constructs in the + * Java language as described in the Java Language + * Specification, Third Edition (JLS3). + * JLS3 is a superset of all earlier versions of the + * Java language, and the JLS3 API can be used to manipulate + * programs written in all versions of the Java language + * up to and including J2SE 5 (aka JDK 1.5). + * + * @since 3.1 + */ + public static final int JLS3 = 3; + + /** + * The binding resolver for this AST. Initially a binding resolver that + * does not resolve names at all. + */ + private BindingResolver resolver = new BindingResolver(); + + /** + * The event handler for this AST. + * Initially an event handler that does not nothing. + * @since 3.0 + */ + private NodeEventHandler eventHandler = new NodeEventHandler(); + + /** + * Level of AST API supported by this AST. + * @since 3.0 + */ + int apiLevel; + + /** + * Internal modification count; initially 0; increases monotonically + * <b>by one or more</b> as the AST is successively modified. + */ + private long modificationCount = 0; + + /** + * Internal original modification count; value is equals to <code> + * modificationCount</code> at the end of the parse (<code>ASTParser + * </code>). If this ast is not created with a parser then value is 0. + * @since 3.0 + */ + private long originalModificationCount = 0; + + /** + * When disableEvents > 0, events are not reported and + * the modification count stays fixed. + * <p> + * This mechanism is used in lazy initialization of a node + * to prevent events from being reported for the modification + * of the node as well as for the creation of the missing child. + * </p> + * @since 3.0 + */ + private int disableEvents = 0; + + /** + * Internal object unique to the AST instance. Readers must synchronize on + * this object when the modifying instance fields. + * @since 3.0 + */ + private final Object internalASTLock = new Object(); + + /** + * Java Scanner used to validate preconditions for the creation of specific nodes + * like CharacterLiteral, NumberLiteral, StringLiteral or SimpleName. + */ + Scanner scanner; + + /** + * Internal ast rewriter used to record ast modification when record mode is enabled. + */ + InternalASTRewrite rewriter; + + /** + * Default value of <code>flag<code> when a new node is created. + */ + private int defaultNodeFlag = 0; + + /** + * Creates a new Java abstract syntax tree + * (AST) following the specified set of API rules. + * + * @param level the API level; one of the LEVEL constants + * @since 3.0 + */ + private AST(int level) { + if ((level != AST.JLS2) + && (level != AST.JLS3)) { + throw new IllegalArgumentException(); + } + this.apiLevel = level; + // initialize a scanner + this.scanner = new Scanner( + true /*comment*/, + true /*whitespace*/, + false /*nls*/, + ClassFileConstants.JDK1_3 /*sourceLevel*/, + ClassFileConstants.JDK1_5 /*complianceLevel*/, + null/*taskTag*/, + null/*taskPriorities*/, + true/*taskCaseSensitive*/); + } + + /** + * Creates a new, empty abstract syntax tree using default options. + * + * @see JavaCore#getDefaultOptions() + * @deprecated Clients should port their code to use the new JLS3 AST API and call + * {@link #newAST(int) AST.newAST(AST.JLS3)} instead of using this constructor. + */ + public AST() { + this(JavaCore.getDefaultOptions()); + } + + /** + * Internal method. + * <p> + * This method converts the given internal compiler AST for the given source string + * into a compilation unit. This method is not intended to be called by clients. + * </p> + * + * @param level the API level; one of the LEVEL constants + * @param compilationUnitDeclaration an internal AST node for a compilation unit declaration + * @param options compiler options + * @param workingCopy the working copy that the AST is created from + * @param monitor the progress monitor used to report progress and request cancellation, + * or <code>null</code> if none + * @param isResolved whether the given compilation unit declaration is resolved + * @return the compilation unit node + * @since 3.4 + * @noreference This method is not intended to be referenced by clients. + */ + public static CompilationUnit convertCompilationUnit( + int level, + org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration compilationUnitDeclaration, + Map options, + boolean isResolved, + org.eclipse.jdt.internal.core.CompilationUnit workingCopy, + int reconcileFlags, + IProgressMonitor monitor) { + + ASTConverter converter = new ASTConverter(options, isResolved, monitor); + AST ast = AST.newAST(level); + int savedDefaultNodeFlag = ast.getDefaultNodeFlag(); + ast.setDefaultNodeFlag(ASTNode.ORIGINAL); + BindingResolver resolver = null; + if (isResolved) { + resolver = new DefaultBindingResolver(compilationUnitDeclaration.scope, workingCopy.owner, new DefaultBindingResolver.BindingTables(), false); + ((DefaultBindingResolver) resolver).isRecoveringBindings = (reconcileFlags & ICompilationUnit.ENABLE_BINDINGS_RECOVERY) != 0; + ast.setFlag(AST.RESOLVED_BINDINGS); + } else { + resolver = new BindingResolver(); + } + ast.setFlag(reconcileFlags); + ast.setBindingResolver(resolver); + converter.setAST(ast); + + CompilationUnit unit = converter.convert(compilationUnitDeclaration, workingCopy.getContents()); + unit.setLineEndTable(compilationUnitDeclaration.compilationResult.getLineSeparatorPositions()); + unit.setTypeRoot(workingCopy.originalFromClone()); + ast.setDefaultNodeFlag(savedDefaultNodeFlag); + return unit; + } + + /** + * Internal method. + * <p> + * This method converts the given internal compiler AST for the given source string + * into a compilation unit. This method is not intended to be called by clients. + * </p> + * + * @param level the API level; one of the LEVEL constants + * @param compilationUnitDeclaration an internal AST node for a compilation unit declaration + * @param source the string of the Java compilation unit + * @param options compiler options + * @param workingCopy the working copy that the AST is created from + * @param monitor the progress monitor used to report progress and request cancellation, + * or <code>null</code> if none + * @param isResolved whether the given compilation unit declaration is resolved + * @return the compilation unit node + * @deprecated Use org.eclipse.jdt.core.dom.AST.convertCompilationUnit(int, CompilationUnitDeclaration, Map, boolean, CompilationUnit, int, IProgressMonitor) instead + * @noreference This method is not intended to be referenced by clients. + */ + public static CompilationUnit convertCompilationUnit( + int level, + org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration compilationUnitDeclaration, + char[] source, + Map options, + boolean isResolved, + org.eclipse.jdt.internal.core.CompilationUnit workingCopy, + int reconcileFlags, + IProgressMonitor monitor) { + return null; + } + + /** + * Creates a new, empty abstract syntax tree using the given options. + * <p> + * Following option keys are significant: + * <ul> + * <li><code>"org.eclipse.jdt.core.compiler.source"</code> - + * indicates source compatibility mode (as per <code>JavaCore</code>); + * <code>"1.3"</code> means the source code is as per JDK 1.3; + * <code>"1.4"</code> means the source code is as per JDK 1.4 + * (<code>"assert"</code> is now a keyword); + * <code>"1.5"</code> means the source code is as per JDK 1.5 + * (<code>"enum"</code> is now a keyword); + * additional legal values may be added later. </li> + * </ul> + * Options other than the above are ignored. + * </p> + * + * @param options the table of options (key type: <code>String</code>; + * value type: <code>String</code>) + * @see JavaCore#getDefaultOptions() + * @deprecated Clients should port their code to use the new JLS3 AST API and call + * {@link #newAST(int) AST.newAST(AST.JLS3)} instead of using this constructor. + */ + public AST(Map options) { + this(JLS2); + Object sourceLevelOption = options.get(JavaCore.COMPILER_SOURCE); + long sourceLevel = ClassFileConstants.JDK1_3; + if (JavaCore.VERSION_1_4.equals(sourceLevelOption)) { + sourceLevel = ClassFileConstants.JDK1_4; + } else if (JavaCore.VERSION_1_5.equals(sourceLevelOption)) { + sourceLevel = ClassFileConstants.JDK1_5; + } + Object complianceLevelOption = options.get(JavaCore.COMPILER_COMPLIANCE); + long complianceLevel = ClassFileConstants.JDK1_3; + if (JavaCore.VERSION_1_4.equals(complianceLevelOption)) { + complianceLevel = ClassFileConstants.JDK1_4; + } else if (JavaCore.VERSION_1_5.equals(complianceLevelOption)) { + complianceLevel = ClassFileConstants.JDK1_5; + } + // override scanner if 1.4 or 1.5 asked for + this.scanner = new Scanner( + true /*comment*/, + true /*whitespace*/, + false /*nls*/, + sourceLevel /*sourceLevel*/, + complianceLevel /*complianceLevel*/, + null/*taskTag*/, + null/*taskPriorities*/, + true/*taskCaseSensitive*/); + } + + /** + * Creates a new Java abstract syntax tree + * (AST) following the specified set of API rules. + * <p> + * Clients should use this method specifing {@link #JLS3} as the + * AST level in all cases, even when dealing with JDK 1.3 or 1.4.. + * </p> + * + * @param level the API level; one of the LEVEL constants + * @return new AST instance following the specified set of API rules. + * @exception IllegalArgumentException if: + * <ul> + * <li>the API level is not one of the LEVEL constants</li> + * </ul> + * @since 3.0 + */ + public static AST newAST(int level) { + if ((level != AST.JLS2) + && (level != AST.JLS3)) { + throw new IllegalArgumentException(); + } + return new AST(level); + } + + /** + * Returns the modification count for this AST. The modification count + * is a non-negative value that increases (by 1 or perhaps by more) as + * this AST or its nodes are changed. The initial value is unspecified. + * <p> + * The following things count as modifying an AST: + * <ul> + * <li>creating a new node owned by this AST,</li> + * <li>adding a child to a node owned by this AST,</li> + * <li>removing a child from a node owned by this AST,</li> + * <li>setting a non-node attribute of a node owned by this AST.</li> + * </ul> + * </p> + * Operations which do not entail creating or modifying existing nodes + * do not increase the modification count. + * <p> + * N.B. This method may be called several times in the course + * of a single client operation. The only promise is that the modification + * count increases monotonically as the AST or its nodes change; there is + * no promise that a modifying operation increases the count by exactly 1. + * </p> + * + * @return the current value (non-negative) of the modification counter of + * this AST + */ + public long modificationCount() { + return this.modificationCount; + } + + /** + * Return the API level supported by this AST. + * + * @return level the API level; one of the <code>JLS*</code>LEVEL + * declared on <code>AST</code>; assume this set is open-ended + * @since 3.0 + */ + public int apiLevel() { + return this.apiLevel; + } + + /** + * Indicates that this AST is about to be modified. + * <p> + * The following things count as modifying an AST: + * <ul> + * <li>creating a new node owned by this AST</li> + * <li>adding a child to a node owned by this AST</li> + * <li>removing a child from a node owned by this AST</li> + * <li>setting a non-node attribute of a node owned by this AST</li>. + * </ul> + * </p> + * <p> + * N.B. This method may be called several times in the course + * of a single client operation. + * </p> + */ + void modifying() { + // when this method is called during lazy init, events are disabled + // and the modification count will not be increased + if (this.disableEvents > 0) { + return; + } + // increase the modification count + this.modificationCount++; + } + + /** + * Disable events. + * This method is thread-safe for AST readers. + * + * @see #reenableEvents() + * @since 3.0 + */ + final void disableEvents() { + synchronized (this.internalASTLock) { + // guard against concurrent access by another reader + this.disableEvents++; + } + // while disableEvents > 0 no events will be reported, and mod count will stay fixed + } + + /** + * Reenable events. + * This method is thread-safe for AST readers. + * + * @see #disableEvents() + * @since 3.0 + */ + final void reenableEvents() { + synchronized (this.internalASTLock) { + // guard against concurrent access by another reader + this.disableEvents--; + } + } + + /** + * Reports that the given node is about to lose a child. + * + * @param node the node about to be modified + * @param child the node about to be removed + * @param property the child or child list property descriptor + * @since 3.0 + */ + void preRemoveChildEvent(ASTNode node, ASTNode child, StructuralPropertyDescriptor property) { + // IMPORTANT: this method is called by readers during lazy init + synchronized (this.internalASTLock) { + // guard against concurrent access by a reader doing lazy init + if (this.disableEvents > 0) { + // doing lazy init OR already processing an event + // System.out.println("[BOUNCE DEL]"); + return; + } else { + disableEvents(); + } + } + try { + this.eventHandler.preRemoveChildEvent(node, child, property); + // N.B. even if event handler blows up, the AST is not + // corrupted since node has not been changed yet + } finally { + reenableEvents(); + } + } + + /** + * Reports that the given node jsut lost a child. + * + * @param node the node that was modified + * @param child the child node that was removed + * @param property the child or child list property descriptor + * @since 3.0 + */ + void postRemoveChildEvent(ASTNode node, ASTNode child, StructuralPropertyDescriptor property) { + // IMPORTANT: this method is called by readers during lazy init + synchronized (this.internalASTLock) { + // guard against concurrent access by a reader doing lazy init + if (this.disableEvents > 0) { + // doing lazy init OR already processing an event + // System.out.println("[BOUNCE DEL]"); + return; + } else { + disableEvents(); + } + } + try { + this.eventHandler.postRemoveChildEvent(node, child, property); + // N.B. even if event handler blows up, the AST is not + // corrupted since node has not been changed yet + } finally { + reenableEvents(); + } + } + + /** + * Reports that the given node is about have a child replaced. + * + * @param node the node about to be modified + * @param child the child node about to be removed + * @param newChild the replacement child + * @param property the child or child list property descriptor + * @since 3.0 + */ + void preReplaceChildEvent(ASTNode node, ASTNode child, ASTNode newChild, StructuralPropertyDescriptor property) { + // IMPORTANT: this method is called by readers during lazy init + synchronized (this.internalASTLock) { + // guard against concurrent access by a reader doing lazy init + if (this.disableEvents > 0) { + // doing lazy init OR already processing an event + // System.out.println("[BOUNCE REP]"); + return; + } else { + disableEvents(); + } + } + try { + this.eventHandler.preReplaceChildEvent(node, child, newChild, property); + // N.B. even if event handler blows up, the AST is not + // corrupted since node has not been changed yet + } finally { + reenableEvents(); + } + } + + /** + * Reports that the given node has just had a child replaced. + * + * @param node the node modified + * @param child the child removed + * @param newChild the replacement child + * @param property the child or child list property descriptor + * @since 3.0 + */ + void postReplaceChildEvent(ASTNode node, ASTNode child, ASTNode newChild, StructuralPropertyDescriptor property) { + // IMPORTANT: this method is called by readers during lazy init + synchronized (this.internalASTLock) { + // guard against concurrent access by a reader doing lazy init + if (this.disableEvents > 0) { + // doing lazy init OR already processing an event + // System.out.println("[BOUNCE REP]"); + return; + } else { + disableEvents(); + } + } + try { + this.eventHandler.postReplaceChildEvent(node, child, newChild, property); + // N.B. even if event handler blows up, the AST is not + // corrupted since node has not been changed yet + } finally { + reenableEvents(); + } + } + + /** + * Reports that the given node is about to gain a child. + * + * @param node the node that to be modified + * @param child the node that to be added as a child + * @param property the child or child list property descriptor + * @since 3.0 + */ + void preAddChildEvent(ASTNode node, ASTNode child, StructuralPropertyDescriptor property) { + // IMPORTANT: this method is called by readers during lazy init + synchronized (this.internalASTLock) { + // guard against concurrent access by a reader doing lazy init + if (this.disableEvents > 0) { + // doing lazy init OR already processing an event + // System.out.println("[BOUNCE ADD]"); + return; + } else { + disableEvents(); + } + } + try { + this.eventHandler.preAddChildEvent(node, child, property); + // N.B. even if event handler blows up, the AST is not + // corrupted since node has already been changed + } finally { + reenableEvents(); + } + } + + /** + * Reports that the given node has just gained a child. + * + * @param node the node that was modified + * @param child the node that was added as a child + * @param property the child or child list property descriptor + * @since 3.0 + */ + void postAddChildEvent(ASTNode node, ASTNode child, StructuralPropertyDescriptor property) { + // IMPORTANT: this method is called by readers during lazy init + synchronized (this.internalASTLock) { + // guard against concurrent access by a reader doing lazy init + if (this.disableEvents > 0) { + // doing lazy init OR already processing an event + // System.out.println("[BOUNCE ADD]"); + return; + } else { + disableEvents(); + } + } + try { + this.eventHandler.postAddChildEvent(node, child, property); + // N.B. even if event handler blows up, the AST is not + // corrupted since node has already been changed + } finally { + reenableEvents(); + } + } + + /** + * Reports that the given node is about to change the value of a + * non-child property. + * + * @param node the node to be modified + * @param property the property descriptor + * @since 3.0 + */ + void preValueChangeEvent(ASTNode node, SimplePropertyDescriptor property) { + // IMPORTANT: this method is called by readers during lazy init + synchronized (this.internalASTLock) { + // guard against concurrent access by a reader doing lazy init + if (this.disableEvents > 0) { + // doing lazy init OR already processing an event + // System.out.println("[BOUNCE CHANGE]"); + return; + } else { + disableEvents(); + } + } + try { + this.eventHandler.preValueChangeEvent(node, property); + // N.B. even if event handler blows up, the AST is not + // corrupted since node has already been changed + } finally { + reenableEvents(); + } + } + + /** + * Reports that the given node has just changed the value of a + * non-child property. + * + * @param node the node that was modified + * @param property the property descriptor + * @since 3.0 + */ + void postValueChangeEvent(ASTNode node, SimplePropertyDescriptor property) { + // IMPORTANT: this method is called by readers during lazy init + synchronized (this.internalASTLock) { + // guard against concurrent access by a reader doing lazy init + if (this.disableEvents > 0) { + // doing lazy init OR already processing an event + // System.out.println("[BOUNCE CHANGE]"); + return; + } else { + disableEvents(); + } + } + try { + this.eventHandler.postValueChangeEvent(node, property); + // N.B. even if event handler blows up, the AST is not + // corrupted since node has already been changed + } finally { + reenableEvents(); + } + } + + /** + * Reports that the given node is about to be cloned. + * + * @param node the node to be cloned + * @since 3.0 + */ + void preCloneNodeEvent(ASTNode node) { + synchronized (this.internalASTLock) { + // guard against concurrent access by a reader doing lazy init + if (this.disableEvents > 0) { + // doing lazy init OR already processing an event + // System.out.println("[BOUNCE CLONE]"); + return; + } else { + disableEvents(); + } + } + try { + this.eventHandler.preCloneNodeEvent(node); + // N.B. even if event handler blows up, the AST is not + // corrupted since node has already been changed + } finally { + reenableEvents(); + } + } + + /** + * Reports that the given node has just been cloned. + * + * @param node the node that was cloned + * @param clone the clone of <code>node</code> + * @since 3.0 + */ + void postCloneNodeEvent(ASTNode node, ASTNode clone) { + synchronized (this.internalASTLock) { + // guard against concurrent access by a reader doing lazy init + if (this.disableEvents > 0) { + // doing lazy init OR already processing an event + // System.out.println("[BOUNCE CLONE]"); + return; + } else { + disableEvents(); + } + } + try { + this.eventHandler.postCloneNodeEvent(node, clone); + // N.B. even if event handler blows up, the AST is not + // corrupted since node has already been changed + } finally { + reenableEvents(); + } + } + + /** + * Parses the source string of the given Java model compilation unit element + * and creates and returns a corresponding abstract syntax tree. The source + * string is obtained from the Java model element using + * <code>ICompilationUnit.getSource()</code>. + * <p> + * The returned compilation unit node is the root node of a new AST. + * Each node in the subtree carries source range(s) information relating back + * to positions in the source string (the source string is not remembered + * with the AST). + * The source range usually begins at the first character of the first token + * corresponding to the node; leading whitespace and comments are <b>not</b> + * included. The source range usually extends through the last character of + * the last token corresponding to the node; trailing whitespace and + * comments are <b>not</b> included. There are a handful of exceptions + * (including compilation units and the various body declarations); the + * specification for these node type spells out the details. + * Source ranges nest properly: the source range for a child is always + * within the source range of its parent, and the source ranges of sibling + * nodes never overlap. + * If a syntax error is detected while parsing, the relevant node(s) of the + * tree will be flagged as <code>MALFORMED</code>. + * </p> + * <p> + * If <code>resolveBindings</code> is <code>true</code>, the various names + * and types appearing in the compilation unit can be resolved to "bindings" + * by calling the <code>resolveBinding</code> methods. These bindings + * draw connections between the different parts of a program, and + * generally afford a more powerful vantage point for clients who wish to + * analyze a program's structure more deeply. These bindings come at a + * considerable cost in both time and space, however, and should not be + * requested frivolously. The additional space is not reclaimed until the + * AST, all its nodes, and all its bindings become garbage. So it is very + * important to not retain any of these objects longer than absolutely + * necessary. Bindings are resolved at the time the AST is created. Subsequent + * modifications to the AST do not affect the bindings returned by + * <code>resolveBinding</code> methods in any way; these methods return the + * same binding as before the AST was modified (including modifications + * that rearrange subtrees by reparenting nodes). + * If <code>resolveBindings</code> is <code>false</code>, the analysis + * does not go beyond parsing and building the tree, and all + * <code>resolveBinding</code> methods return <code>null</code> from the + * outset. + * </p> + * + * @param unit the Java model compilation unit whose source code is to be parsed + * @param resolveBindings <code>true</code> if bindings are wanted, + * and <code>false</code> if bindings are not of interest + * @return the compilation unit node + * @exception IllegalArgumentException if the given Java element does not + * exist or if its source string cannot be obtained + * @see ASTNode#getFlags() + * @see ASTNode#MALFORMED + * @see ASTNode#getStartPosition() + * @see ASTNode#getLength() + * @since 2.0 + * @deprecated Use {@link ASTParser} instead. + */ + public static CompilationUnit parseCompilationUnit( + ICompilationUnit unit, + boolean resolveBindings) { + + try { + ASTParser c = ASTParser.newParser(AST.JLS2); + c.setSource(unit); + c.setResolveBindings(resolveBindings); + ASTNode result = c.createAST(null); + return (CompilationUnit) result; + } catch (IllegalStateException e) { + // convert ASTParser's complaints into old form + throw new IllegalArgumentException(); + } + } + + /** + * Parses the source string corresponding to the given Java class file + * element and creates and returns a corresponding abstract syntax tree. + * The source string is obtained from the Java model element using + * <code>IClassFile.getSource()</code>, and is only available for a class + * files with attached source. + * <p> + * The returned compilation unit node is the root node of a new AST. + * Each node in the subtree carries source range(s) information relating back + * to positions in the source string (the source string is not remembered + * with the AST). + * The source range usually begins at the first character of the first token + * corresponding to the node; leading whitespace and comments are <b>not</b> + * included. The source range usually extends through the last character of + * the last token corresponding to the node; trailing whitespace and + * comments are <b>not</b> included. There are a handful of exceptions + * (including compilation units and the various body declarations); the + * specification for these node type spells out the details. + * Source ranges nest properly: the source range for a child is always + * within the source range of its parent, and the source ranges of sibling + * nodes never overlap. + * If a syntax error is detected while parsing, the relevant node(s) of the + * tree will be flagged as <code>MALFORMED</code>. + * </p> + * <p> + * If <code>resolveBindings</code> is <code>true</code>, the various names + * and types appearing in the compilation unit can be resolved to "bindings" + * by calling the <code>resolveBinding</code> methods. These bindings + * draw connections between the different parts of a program, and + * generally afford a more powerful vantage point for clients who wish to + * analyze a program's structure more deeply. These bindings come at a + * considerable cost in both time and space, however, and should not be + * requested frivolously. The additional space is not reclaimed until the + * AST, all its nodes, and all its bindings become garbage. So it is very + * important to not retain any of these objects longer than absolutely + * necessary. Bindings are resolved at the time the AST is created. Subsequent + * modifications to the AST do not affect the bindings returned by + * <code>resolveBinding</code> methods in any way; these methods return the + * same binding as before the AST was modified (including modifications + * that rearrange subtrees by reparenting nodes). + * If <code>resolveBindings</code> is <code>false</code>, the analysis + * does not go beyond parsing and building the tree, and all + * <code>resolveBinding</code> methods return <code>null</code> from the + * outset. + * </p> + * + * @param classFile the Java model class file whose corresponding source code is to be parsed + * @param resolveBindings <code>true</code> if bindings are wanted, + * and <code>false</code> if bindings are not of interest + * @return the compilation unit node + * @exception IllegalArgumentException if the given Java element does not + * exist or if its source string cannot be obtained + * @see ASTNode#getFlags() + * @see ASTNode#MALFORMED + * @see ASTNode#getStartPosition() + * @see ASTNode#getLength() + * @since 2.1 + * @deprecated Use {@link ASTParser} instead. + */ + public static CompilationUnit parseCompilationUnit( + IClassFile classFile, + boolean resolveBindings) { + + if (classFile == null) { + throw new IllegalArgumentException(); + } + try { + ASTParser c = ASTParser.newParser(AST.JLS2); + c.setSource(classFile); + c.setResolveBindings(resolveBindings); + ASTNode result = c.createAST(null); + return (CompilationUnit) result; + } catch (IllegalStateException e) { + // convert ASTParser's complaints into old form + throw new IllegalArgumentException(); + } + } + + /** + * Parses the given string as the hypothetical contents of the named + * compilation unit and creates and returns a corresponding abstract syntax tree. + * <p> + * The returned compilation unit node is the root node of a new AST. + * Each node in the subtree carries source range(s) information relating back + * to positions in the given source string (the given source string itself + * is not remembered with the AST). + * The source range usually begins at the first character of the first token + * corresponding to the node; leading whitespace and comments are <b>not</b> + * included. The source range usually extends through the last character of + * the last token corresponding to the node; trailing whitespace and + * comments are <b>not</b> included. There are a handful of exceptions + * (including compilation units and the various body declarations); the + * specification for these node type spells out the details. + * Source ranges nest properly: the source range for a child is always + * within the source range of its parent, and the source ranges of sibling + * nodes never overlap. + * If a syntax error is detected while parsing, the relevant node(s) of the + * tree will be flagged as <code>MALFORMED</code>. + * </p> + * <p> + * If the given project is not <code>null</code>, the various names + * and types appearing in the compilation unit can be resolved to "bindings" + * by calling the <code>resolveBinding</code> methods. These bindings + * draw connections between the different parts of a program, and + * generally afford a more powerful vantage point for clients who wish to + * analyze a program's structure more deeply. These bindings come at a + * considerable cost in both time and space, however, and should not be + * requested frivolously. The additional space is not reclaimed until the + * AST, all its nodes, and all its bindings become garbage. So it is very + * important to not retain any of these objects longer than absolutely + * necessary. Bindings are resolved at the time the AST is created. Subsequent + * modifications to the AST do not affect the bindings returned by + * <code>resolveBinding</code> methods in any way; these methods return the + * same binding as before the AST was modified (including modifications + * that rearrange subtrees by reparenting nodes). + * If the given project is <code>null</code>, the analysis + * does not go beyond parsing and building the tree, and all + * <code>resolveBinding</code> methods return <code>null</code> from the + * outset. + * </p> + * <p> + * The name of the compilation unit must be supplied for resolving bindings. + * This name should be suffixed by a dot ('.') followed by one of the + * {@link JavaCore#getJavaLikeExtensions() Java-like extensions} + * and match the name of the main + * (public) class or interface declared in the source. For example, if the source + * declares a public class named "Foo", the name of the compilation can be + * "Foo.java". For the purposes of resolving bindings, types declared in the + * source string hide types by the same name available through the classpath + * of the given project. + * </p> + * + * @param source the string to be parsed as a Java compilation unit + * @param unitName the name of the compilation unit that would contain the source + * string, or <code>null</code> if <code>javaProject</code> is also <code>null</code> + * @param project the Java project used to resolve names, or + * <code>null</code> if bindings are not resolved + * @return the compilation unit node + * @see ASTNode#getFlags() + * @see ASTNode#MALFORMED + * @see ASTNode#getStartPosition() + * @see ASTNode#getLength() + * @since 2.0 + * @deprecated Use {@link ASTParser} instead. + */ + public static CompilationUnit parseCompilationUnit( + char[] source, + String unitName, + IJavaProject project) { + + if (source == null) { + throw new IllegalArgumentException(); + } + ASTParser astParser = ASTParser.newParser(AST.JLS2); + astParser.setSource(source); + astParser.setUnitName(unitName); + astParser.setProject(project); + astParser.setResolveBindings(project != null); + ASTNode result = astParser.createAST(null); + return (CompilationUnit) result; + } + + /** + * Parses the given string as a Java compilation unit and creates and + * returns a corresponding abstract syntax tree. + * <p> + * The returned compilation unit node is the root node of a new AST. + * Each node in the subtree carries source range(s) information relating back + * to positions in the given source string (the given source string itself + * is not remembered with the AST). + * The source range usually begins at the first character of the first token + * corresponding to the node; leading whitespace and comments are <b>not</b> + * included. The source range usually extends through the last character of + * the last token corresponding to the node; trailing whitespace and + * comments are <b>not</b> included. There are a handful of exceptions + * (including compilation units and the various body declarations); the + * specification for these node type spells out the details. + * Source ranges nest properly: the source range for a child is always + * within the source range of its parent, and the source ranges of sibling + * nodes never overlap. + * If a syntax error is detected while parsing, the relevant node(s) of the + * tree will be flagged as <code>MALFORMED</code>. + * </p> + * <p> + * This method does not compute binding information; all <code>resolveBinding</code> + * methods applied to nodes of the resulting AST return <code>null</code>. + * </p> + * + * @param source the string to be parsed as a Java compilation unit + * @return the compilation unit node + * @see ASTNode#getFlags() + * @see ASTNode#MALFORMED + * @see ASTNode#getStartPosition() + * @see ASTNode#getLength() + * @since 2.0 + * @deprecated Use {@link ASTParser} instead. + */ + public static CompilationUnit parseCompilationUnit(char[] source) { + if (source == null) { + throw new IllegalArgumentException(); + } + ASTParser c = ASTParser.newParser(AST.JLS2); + c.setSource(source); + ASTNode result = c.createAST(null); + return (CompilationUnit) result; + } + + /** + * Returns the binding resolver for this AST. + * + * @return the binding resolver for this AST + */ + BindingResolver getBindingResolver() { + return this.resolver; + } + + /** + * Returns the event handler for this AST. + * + * @return the event handler for this AST + * @since 3.0 + */ + NodeEventHandler getEventHandler() { + return this.eventHandler; + } + + /** + * Sets the event handler for this AST. + * + * @param eventHandler the event handler for this AST + * @since 3.0 + */ + void setEventHandler(NodeEventHandler eventHandler) { + if (this.eventHandler == null) { + throw new IllegalArgumentException(); + } + this.eventHandler = eventHandler; + } + + /** + * Returns default node flags of new nodes of this AST. + * + * @return the default node flags of new nodes of this AST + * @since 3.0 + */ + int getDefaultNodeFlag() { + return this.defaultNodeFlag; + } + + /** + * Sets default node flags of new nodes of this AST. + * + * @param flag node flags of new nodes of this AST + * @since 3.0 + */ + void setDefaultNodeFlag(int flag) { + this.defaultNodeFlag = flag; + } + + /** + * Set <code>originalModificationCount</code> to the current modification count + * + * @since 3.0 + */ + void setOriginalModificationCount(long count) { + this.originalModificationCount = count; + } + + /** + * Returns the type binding for a "well known" type. + * <p> + * Note that bindings are generally unavailable unless requested when the + * AST is being built. + * </p> + * <p> + * The following type names are supported: + * <ul> + * <li><code>"boolean"</code></li> + * <li><code>"byte"</code></li> + * <li><code>"char"</code></li> + * <li><code>"double"</code></li> + * <li><code>"float"</code></li> + * <li><code>"int"</code></li> + * <li><code>"long"</code></li> + * <li><code>"short"</code></li> + * <li><code>"void"</code></li> + * <li><code>"java.lang.Boolean"</code> (since 3.1)</li> + * <li><code>"java.lang.Byte"</code> (since 3.1)</li> + * <li><code>"java.lang.Character"</code> (since 3.1)</li> + * <li><code>"java.lang.Class"</code></li> + * <li><code>"java.lang.Cloneable"</code></li> + * <li><code>"java.lang.Double"</code> (since 3.1)</li> + * <li><code>"java.lang.Error"</code></li> + * <li><code>"java.lang.Exception"</code></li> + * <li><code>"java.lang.Float"</code> (since 3.1)</li> + * <li><code>"java.lang.Integer"</code> (since 3.1)</li> + * <li><code>"java.lang.Long"</code> (since 3.1)</li> + * <li><code>"java.lang.Object"</code></li> + * <li><code>"java.lang.RuntimeException"</code></li> + * <li><code>"java.lang.Short"</code> (since 3.1)</li> + * <li><code>"java.lang.String"</code></li> + * <li><code>"java.lang.StringBuffer"</code></li> + * <li><code>"java.lang.Throwable"</code></li> + * <li><code>"java.lang.Void"</code> (since 3.1)</li> + * <li><code>"java.io.Serializable"</code></li> + * </ul> + * </p> + * + * @param name the name of a well known type + * @return the corresponding type binding, or <code>null</code> if the + * named type is not considered well known or if no binding can be found + * for it + */ + public ITypeBinding resolveWellKnownType(String name) { + if (name == null) { + return null; + } + return getBindingResolver().resolveWellKnownType(name); + } + + /** + * Sets the binding resolver for this AST. + * + * @param resolver the new binding resolver for this AST + */ + void setBindingResolver(BindingResolver resolver) { + if (resolver == null) { + throw new IllegalArgumentException(); + } + this.resolver = resolver; + } + + /** + * Checks that this AST operation is not used when + * building level JLS2 ASTs. + + * @exception UnsupportedOperationException + * @since 3.0 + */ + void unsupportedIn2() { + if (this.apiLevel == AST.JLS2) { + throw new UnsupportedOperationException("Operation not supported in JLS2 AST"); //$NON-NLS-1$ + } + } + + /** + * Checks that this AST operation is only used when + * building level JLS2 ASTs. + + * @exception UnsupportedOperationException + * @since 3.0 + */ + void supportedOnlyIn2() { + if (this.apiLevel != AST.JLS2) { + throw new UnsupportedOperationException("Operation not supported in JLS2 AST"); //$NON-NLS-1$ + } + } + + /** + * new Class[] {AST.class} + * @since 3.0 + */ + private static final Class[] AST_CLASS = new Class[] {AST.class}; + + /** + * new Object[] {this} + * @since 3.0 + */ + private final Object[] THIS_AST= new Object[] {this}; + + /* + * Must not collide with a value for ICompilationUnit constants + */ + static final int RESOLVED_BINDINGS = 0x80000000; + + /** + * Tag bit value. This represents internal state of the tree. + */ + private int bits; + + /** + * Creates an unparented node of the given node class + * (non-abstract subclass of {@link ASTNode}). + * + * @param nodeClass AST node class + * @return a new unparented node owned by this AST + * @exception IllegalArgumentException if <code>nodeClass</code> is + * <code>null</code> or is not a concrete node type class + * @since 3.0 + */ + public ASTNode createInstance(Class nodeClass) { + if (nodeClass == null) { + throw new IllegalArgumentException(); + } + try { + // invoke constructor with signature Foo(AST) + Constructor c = nodeClass.getDeclaredConstructor(AST_CLASS); + Object result = c.newInstance(this.THIS_AST); + return (ASTNode) result; + } catch (NoSuchMethodException e) { + // all AST node classes have a Foo(AST) constructor + // therefore nodeClass is not legit + throw new IllegalArgumentException(); + } catch (InstantiationException e) { + // all concrete AST node classes can be instantiated + // therefore nodeClass is not legit + throw new IllegalArgumentException(); + } catch (IllegalAccessException e) { + // all AST node classes have an accessible Foo(AST) constructor + // therefore nodeClass is not legit + throw new IllegalArgumentException(); + } catch (InvocationTargetException e) { + // concrete AST node classes do not die in the constructor + // therefore nodeClass is not legit + throw new IllegalArgumentException(); + } + } + + /** + * Creates an unparented node of the given node type. + * This convenience method is equivalent to: + * <pre> + * createInstance(ASTNode.nodeClassForType(nodeType)) + * </pre> + * + * @param nodeType AST node type, one of the node type + * constants declared on {@link ASTNode} + * @return a new unparented node owned by this AST + * @exception IllegalArgumentException if <code>nodeType</code> is + * not a legal AST node type + * @since 3.0 + */ + public ASTNode createInstance(int nodeType) { + // nodeClassForType throws IllegalArgumentException if nodeType is bogus + Class nodeClass = ASTNode.nodeClassForType(nodeType); + return createInstance(nodeClass); + } + + //=============================== NAMES =========================== + /** + * Creates and returns a new unparented simple name node for the given + * identifier. The identifier should be a legal Java identifier, but not + * a keyword, boolean literal ("true", "false") or null literal ("null"). + * + * @param identifier the identifier + * @return a new unparented simple name node + * @exception IllegalArgumentException if the identifier is invalid + */ + public SimpleName newSimpleName(String identifier) { + if (identifier == null) { + throw new IllegalArgumentException(); + } + SimpleName result = new SimpleName(this); + result.setIdentifier(identifier); + return result; + } + + /** + * Creates and returns a new unparented qualified name node for the given + * qualifier and simple name child node. + * + * @param qualifier the qualifier name node + * @param name the simple name being qualified + * @return a new unparented qualified name node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public QualifiedName newQualifiedName( + Name qualifier, + SimpleName name) { + QualifiedName result = new QualifiedName(this); + result.setQualifier(qualifier); + result.setName(name); + return result; + + } + + /** + * Creates and returns a new unparented name node for the given name + * segments. Returns a simple name if there is only one name segment, and + * a qualified name if there are multiple name segments. Each of the name + * segments should be legal Java identifiers (this constraint may or may + * not be enforced), and there must be at least one name segment. + * + * @param identifiers a list of 1 or more name segments, each of which + * is a legal Java identifier + * @return a new unparented name node + * @exception IllegalArgumentException if: + * <ul> + * <li>the identifier is invalid</li> + * <li>the list of identifiers is empty</li> + * </ul> + */ + public Name newName(String[] identifiers) { + // update internalSetName(String[] if changed + int count = identifiers.length; + if (count == 0) { + throw new IllegalArgumentException(); + } + Name result = newSimpleName(identifiers[0]); + for (int i = 1; i < count; i++) { + SimpleName name = newSimpleName(identifiers[i]); + result = newQualifiedName(result, name); + } + return result; + } + + /* (omit javadoc for this method) + * This method is a copy of setName(String[]) that doesn't do any validation. + */ + Name internalNewName(String[] identifiers) { + int count = identifiers.length; + if (count == 0) { + throw new IllegalArgumentException(); + } + final SimpleName simpleName = new SimpleName(this); + simpleName.internalSetIdentifier(identifiers[0]); + Name result = simpleName; + for (int i = 1; i < count; i++) { + SimpleName name = new SimpleName(this); + name.internalSetIdentifier(identifiers[i]); + result = newQualifiedName(result, name); + } + return result; + } + + /** + * Creates and returns a new unparented name node for the given name. + * The name string must consist of 1 or more name segments separated + * by single dots '.'. Returns a {@link QualifiedName} if the name has + * dots, and a {@link SimpleName} otherwise. Each of the name + * segments should be legal Java identifiers (this constraint may or may + * not be enforced), and there must be at least one name segment. + * The string must not contains white space, '<', '>', + * '[', ']', or other any other characters that are not + * part of the Java identifiers or separating '.'s. + * + * @param qualifiedName string consisting of 1 or more name segments, + * each of which is a legal Java identifier, separated by single dots '.' + * @return a new unparented name node + * @exception IllegalArgumentException if: + * <ul> + * <li>the string is empty</li> + * <li>the string begins or ends in a '.'</li> + * <li>the string has adjacent '.'s</li> + * <li>the segments between the '.'s are not valid Java identifiers</li> + * </ul> + * @since 3.1 + */ + public Name newName(String qualifiedName) { + StringTokenizer t = new StringTokenizer(qualifiedName, ".", true); //$NON-NLS-1$ + Name result = null; + // balance is # of name tokens - # of period tokens seen so far + // initially 0; finally 1; should never drop < 0 or > 1 + int balance = 0; + while(t.hasMoreTokens()) { + String s = t.nextToken(); + if (s.indexOf('.') >= 0) { + // this is a delimiter + if (s.length() > 1) { + // too many dots in a row + throw new IllegalArgumentException(); + } + balance--; + if (balance < 0) { + throw new IllegalArgumentException(); + } + } else { + // this is an identifier segment + balance++; + SimpleName name = newSimpleName(s); + if (result == null) { + result = name; + } else { + result = newQualifiedName(result, name); + } + } + } + if (balance != 1) { + throw new IllegalArgumentException(); + } + return result; + } +//{ObjectTeams: factories for faked resolved name: + // Note, these methods are implemented here, because they need access to some + // package-private features. + /** This method creates a new dom-AST SimpleName that can be resolved to the same type as the provided <code>type</code>. + * the binding be of kind VARIABLE. */ + public SimpleName newResolvedVariableName(String name, Type type) { + DefaultBindingResolver resolver = (DefaultBindingResolver)this.resolver; + org.eclipse.jdt.internal.compiler.ast.Expression givenCompilerNode = + (org.eclipse.jdt.internal.compiler.ast.Expression)resolver.newAstToOldAst.get(type); + long pos = ((long)givenCompilerNode.sourceStart << 32) + givenCompilerNode.sourceEnd; + return createMappedVariableNode(name, givenCompilerNode.resolvedType, pos); + } + public SimpleName newResolvedVariableName(String name, TypeDeclaration type) { + DefaultBindingResolver resolver = (DefaultBindingResolver)this.resolver; + org.eclipse.jdt.internal.compiler.ast.TypeDeclaration givenCompilerNode = + (org.eclipse.jdt.internal.compiler.ast.TypeDeclaration)resolver.newAstToOldAst.get(type); + long pos = ((long)givenCompilerNode.sourceStart << 32) + givenCompilerNode.sourceEnd; + return createMappedVariableNode(name, givenCompilerNode.binding, pos); + } + + private SimpleName createMappedVariableNode(String name, + org.eclipse.jdt.internal.compiler.lookup.TypeBinding typeBinding, + long pos) + { + org.eclipse.jdt.internal.compiler.ast.SingleNameReference newCompilerNode + = new org.eclipse.jdt.internal.compiler.ast.SingleNameReference(name.toCharArray(), pos); + newCompilerNode.resolvedType = typeBinding; + newCompilerNode.binding = new LocalVariableBinding(name.toCharArray(), typeBinding, 0, false); + SimpleName result = newSimpleName(name); + this.resolver.store(result, newCompilerNode); + return result; + } +// SH} + + //=============================== TYPES =========================== + /** + * Creates and returns a new unparented simple type node with the given + * type name. + * <p> + * This method can be used to convert a name (<code>Name</code>) into a + * type (<code>Type</code>) by wrapping it. + * </p> + * + * @param typeName the name of the class or interface + * @return a new unparented simple type node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public SimpleType newSimpleType(Name typeName) { + SimpleType result = new SimpleType(this); + result.setName(typeName); + return result; + } + + /** + * Creates and returns a new unparented array type node with the given + * component type, which may be another array type. + * + * @param componentType the component type (possibly another array type) + * @return a new unparented array type node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public ArrayType newArrayType(Type componentType) { + ArrayType result = new ArrayType(this); + result.setComponentType(componentType); + return result; + } + + /** + * Creates and returns a new unparented array type node with the given + * element type and number of dimensions. + * <p> + * Note that if the element type passed in is an array type, the + * element type of the result will not be the same as what was passed in. + * </p> + * + * @param elementType the element type (never an array type) + * @param dimensions the number of dimensions, a positive number + * @return a new unparented array type node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * <li>the element type is null</li> + * <li>the element type is an array type</li> + * <li>the number of dimensions is lower than 1</li> + * <li>the number of dimensions is greater than 1000</li> + * </ul> + */ + public ArrayType newArrayType(Type elementType, int dimensions) { + if (elementType == null || elementType.isArrayType()) { + throw new IllegalArgumentException(); + } + if (dimensions < 1 || dimensions > 1000) { + // we would blow our stacks anyway with a 1000-D array + throw new IllegalArgumentException(); + } + ArrayType result = new ArrayType(this); + result.setComponentType(elementType); + for (int i = 2; i <= dimensions; i++) { + result = newArrayType(result); + } + return result; + + } + + /** + * Creates and returns a new unparented primitive type node with the given + * type code. + * + * @param typeCode one of the primitive type code constants declared in + * <code>PrimitiveType</code> + * @return a new unparented primitive type node + * @exception IllegalArgumentException if the primitive type code is invalid + */ + public PrimitiveType newPrimitiveType(PrimitiveType.Code typeCode) { + PrimitiveType result = new PrimitiveType(this); + result.setPrimitiveTypeCode(typeCode); + return result; + } + + /** + * Creates and returns a new unparented parameterized type node with the + * given type and an empty list of type arguments. + * + * @param type the type that is parameterized + * @return a new unparented parameterized type node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + * @exception UnsupportedOperationException if this operation is used in + * a JLS2 AST + * @since 3.1 + */ + public ParameterizedType newParameterizedType(Type type) { + ParameterizedType result = new ParameterizedType(this); + result.setType(type); + return result; + } + +//{ObjectTeams: type anchor to be used with ParameterizedType: + public TypeAnchor newTypeAnchor(Name path) { + TypeAnchor result = new TypeAnchor(this); + result.setPath(path); + return result; + } +// SH} + + /** + * Creates and returns a new unparented qualified type node with + * the given qualifier type and name. + * + * @param qualifier the qualifier type node + * @param name the simple name being qualified + * @return a new unparented qualified type node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + * @exception UnsupportedOperationException if this operation is used in + * a JLS2 AST + * @since 3.1 + */ + public QualifiedType newQualifiedType(Type qualifier, SimpleName name) { + QualifiedType result = new QualifiedType(this); + result.setQualifier(qualifier); + result.setName(name); + return result; + } + + /** + * Creates and returns a new unparented wildcard type node with no + * type bound. + * + * @return a new unparented wildcard type node + * @exception UnsupportedOperationException if this operation is used in + * a JLS2 AST + * @since 3.1 + */ + public WildcardType newWildcardType() { + WildcardType result = new WildcardType(this); + return result; + } + +//{ObjectTeams: factory method for LiftingType + /** + * Creates and returns a new unparented lifting type node with the given + * type name. + * + * @param typeName the name of the class or interface + * @return a new unparented lifting type node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public LiftingType newLiftingType(Name typeName) + { + LiftingType result = new LiftingType(this); + result.setName(typeName); + return result; + } +//gbr} + + //=============================== DECLARATIONS =========================== + /** + * Creates an unparented compilation unit node owned by this AST. + * The compilation unit initially has no package declaration, no + * import declarations, and no type declarations. + * + * @return the new unparented compilation unit node + */ + public CompilationUnit newCompilationUnit() { + return new CompilationUnit(this); + } + + /** + * Creates an unparented package declaration node owned by this AST. + * The package declaration initially declares a package with an + * unspecified name. + * + * @return the new unparented package declaration node + */ + public PackageDeclaration newPackageDeclaration() { + PackageDeclaration result = new PackageDeclaration(this); + return result; + } + + /** + * Creates an unparented import declaration node owned by this AST. + * The import declaration initially contains a single-type import + * of a type with an unspecified name. + * + * @return the new unparented import declaration node + */ + public ImportDeclaration newImportDeclaration() { + ImportDeclaration result = new ImportDeclaration(this); + return result; + } + + /** + * Creates an unparented class declaration node owned by this AST. + * The name of the class is an unspecified, but legal, name; + * no modifiers; no doc comment; no superclass or superinterfaces; + * and an empty class body. + * <p> + * To create an interface, use this method and then call + * <code>TypeDeclaration.setInterface(true)</code>. + * </p> + * + * @return a new unparented type declaration node + */ + public TypeDeclaration newTypeDeclaration() { + TypeDeclaration result = new TypeDeclaration(this); + result.setInterface(false); + return result; + } + +//{ObjectTeams: + /** + * Creates an unparented class declaration node owned by this AST. + * The name of the class is an unspecified, but legal, name; + * no modifiers; no doc comment; no superclass or superinterfaces; + * and an empty class body. + * <p> + * To create an interface, use this method and then call + * <code>RoleTypeDeclaration.setInterface(true)</code>. + * </p> + * + * @return a new unparented roleType declaration node + */ + public RoleTypeDeclaration newRoleTypeDeclaration() { + RoleTypeDeclaration result = new RoleTypeDeclaration(this); + return result; + } + + public PrecedenceDeclaration newPrecedenceDeclaration() { + return new PrecedenceDeclaration(this); + } + + public GuardPredicateDeclaration newGuardPredicateDeclaration () { + return new GuardPredicateDeclaration(this); + } +// km(merge) } + + /** + * Creates an unparented method declaration node owned by this AST. + * By default, the declaration is for a method of an unspecified, but + * legal, name; no modifiers; no doc comment; no parameters; return + * type void; no extra array dimensions; no thrown exceptions; and no + * body (as opposed to an empty body). + * <p> + * To create a constructor, use this method and then call + * <code>MethodDeclaration.setConstructor(true)</code> and + * <code>MethodDeclaration.setName(className)</code>. + * </p> + * + * @return a new unparented method declaration node + */ + public MethodDeclaration newMethodDeclaration() { + MethodDeclaration result = new MethodDeclaration(this); + result.setConstructor(false); + return result; + } + + /** + * Creates an unparented single variable declaration node owned by this AST. + * By default, the declaration is for a variable with an unspecified, but + * legal, name and type; no modifiers; no array dimensions after the + * variable; no initializer; not variable arity. + * + * @return a new unparented single variable declaration node + */ + public SingleVariableDeclaration newSingleVariableDeclaration() { + SingleVariableDeclaration result = new SingleVariableDeclaration(this); + return result; + } + + /** + * Creates an unparented variable declaration fragment node owned by this + * AST. By default, the fragment is for a variable with an unspecified, but + * legal, name; no extra array dimensions; and no initializer. + * + * @return a new unparented variable declaration fragment node + */ + public VariableDeclarationFragment newVariableDeclarationFragment() { + VariableDeclarationFragment result = new VariableDeclarationFragment(this); + return result; + } + + /** + * Creates an unparented initializer node owned by this AST, with an + * empty block. By default, the initializer has no modifiers and + * an empty block. + * + * @return a new unparented initializer node + */ + public Initializer newInitializer() { + Initializer result = new Initializer(this); + return result; + } + + /** + * Creates an unparented enum constant declaration node owned by this AST. + * The name of the constant is an unspecified, but legal, name; + * no doc comment; no modifiers or annotations; no arguments; + * and does not declare an anonymous class. + * + * @return a new unparented enum constant declaration node + * @exception UnsupportedOperationException if this operation is used in + * a JLS2 AST + * @since 3.1 + */ + public EnumConstantDeclaration newEnumConstantDeclaration() { + EnumConstantDeclaration result = new EnumConstantDeclaration(this); + return result; + } + + /** + * Creates an unparented enum declaration node owned by this AST. + * The name of the enum is an unspecified, but legal, name; + * no doc comment; no modifiers or annotations; + * no superinterfaces; and empty lists of enum constants + * and body declarations. + * + * @return a new unparented enum declaration node + * @exception UnsupportedOperationException if this operation is used in + * a JLS2 AST + * @since 3.1 + */ + public EnumDeclaration newEnumDeclaration() { + EnumDeclaration result = new EnumDeclaration(this); + return result; + } + + /** + * Creates and returns a new unparented type parameter type node with an + * unspecified type variable name and an empty list of type bounds. + * + * @return a new unparented type parameter node + * @exception UnsupportedOperationException if this operation is used in + * a JLS2 AST + * @since 3.1 + */ + public TypeParameter newTypeParameter() { + TypeParameter result = new TypeParameter(this); + return result; + } + + /** + * Creates and returns a new unparented annotation type declaration + * node for an unspecified, but legal, name; no modifiers; no javadoc; + * and an empty list of member declarations. + * + * @return a new unparented annotation type declaration node + * @exception UnsupportedOperationException if this operation is used in + * a JLS2 AST + * @since 3.1 + */ + public AnnotationTypeDeclaration newAnnotationTypeDeclaration() { + AnnotationTypeDeclaration result = new AnnotationTypeDeclaration(this); + return result; + } + + /** + * Creates and returns a new unparented annotation type + * member declaration node for an unspecified, but legal, + * member name and type; no modifiers; no javadoc; + * and no default value. + * + * @return a new unparented annotation type member declaration node + * @exception UnsupportedOperationException if this operation is used in + * a JLS2 AST + * @since 3.1 + */ + public AnnotationTypeMemberDeclaration newAnnotationTypeMemberDeclaration() { + AnnotationTypeMemberDeclaration result = new AnnotationTypeMemberDeclaration(this); + return result; + } + + /** + * Creates and returns a new unparented modifier node for the given + * modifier. + * + * @param keyword one of the modifier keyword constants + * @return a new unparented modifier node + * @exception IllegalArgumentException if the primitive type code is invalid + * @exception UnsupportedOperationException if this operation is used in + * a JLS2 AST + * @since 3.1 + */ + public Modifier newModifier(Modifier.ModifierKeyword keyword) { + Modifier result = new Modifier(this); + result.setKeyword(keyword); + return result; + } + + /** + * Creates and returns a list of new unparented modifier nodes + * for the given modifier flags. When multiple modifiers are + * requested the modifiers nodes will appear in the following order: + * public, protected, private, abstract, static, final, synchronized, + * native, strictfp, transient, volatile. This order is consistent + * with the recommendations in JLS2 8.1.1, 8.3.1, and 8.4.3. + * + * @param flags bitwise or of modifier flags declared on {@link Modifier} + * @return a possibly empty list of new unparented modifier nodes + * (element type <code>Modifier</code>) + * @exception UnsupportedOperationException if this operation is used in + * a JLS2 AST + * @since 3.1 + */ + public List newModifiers(int flags) { + if (this.apiLevel == AST.JLS2) { + unsupportedIn2(); + } + List result = new ArrayList(3); // 3 modifiers is more than average + if (Modifier.isPublic(flags)) { + result.add(newModifier(Modifier.ModifierKeyword.PUBLIC_KEYWORD)); + } + if (Modifier.isProtected(flags)) { + result.add(newModifier(Modifier.ModifierKeyword.PROTECTED_KEYWORD)); + } + if (Modifier.isPrivate(flags)) { + result.add(newModifier(Modifier.ModifierKeyword.PRIVATE_KEYWORD)); + } + if (Modifier.isAbstract(flags)) { + result.add(newModifier(Modifier.ModifierKeyword.ABSTRACT_KEYWORD)); + } + if (Modifier.isStatic(flags)) { + result.add(newModifier(Modifier.ModifierKeyword.STATIC_KEYWORD)); + } + if (Modifier.isFinal(flags)) { + result.add(newModifier(Modifier.ModifierKeyword.FINAL_KEYWORD)); + } + if (Modifier.isSynchronized(flags)) { + result.add(newModifier(Modifier.ModifierKeyword.SYNCHRONIZED_KEYWORD)); + } + if (Modifier.isNative(flags)) { + result.add(newModifier(Modifier.ModifierKeyword.NATIVE_KEYWORD)); + } + if (Modifier.isStrictfp(flags)) { + result.add(newModifier(Modifier.ModifierKeyword.STRICTFP_KEYWORD)); + } + if (Modifier.isTransient(flags)) { + result.add(newModifier(Modifier.ModifierKeyword.TRANSIENT_KEYWORD)); + } + if (Modifier.isVolatile(flags)) { + result.add(newModifier(Modifier.ModifierKeyword.VOLATILE_KEYWORD)); + } +//{ObjectTeams: OT-specific modifiers (any context): + if (Modifier.isReplace(flags) || Modifier.isBefore(flags) || Modifier.isAfter(flags)) + throw new IllegalArgumentException("not applicable for callin modifiers"); //$NON-NLS-1$ + + if (Modifier.isGet(flags)) { + result.add(newModifier(Modifier.ModifierKeyword.GET_KEYWORD)); + } + if (Modifier.isSet(flags)) { + result.add(newModifier(Modifier.ModifierKeyword.SET_KEYWORD)); + } + if (Modifier.isTeam(flags)) { + result.add(newModifier(Modifier.ModifierKeyword.TEAM_KEYWORD)); + } + if (Modifier.isCallin(flags)) { + result.add(newModifier(Modifier.ModifierKeyword.CALLIN_KEYWORD)); + } +// SH} + return result; + } + +//{ObjectTeams: factory methods for CallinMappingDeclaration and CalloutMappingDeclaration + /** + * Creates an unparented callin mapping declaration node owned by this AST. + * The binding kind is set to {@link MethodBindingOperator#KIND_CALLIN} + * + * @return a new unparented callin mapping declaration node + */ + public CallinMappingDeclaration newCallinMappingDeclaration() + { + CallinMappingDeclaration callinMappingDeclaration = new CallinMappingDeclaration(this); + callinMappingDeclaration.bindingOperator().setBindingKind(MethodBindingOperator.KIND_CALLIN); + return callinMappingDeclaration; + } + + /** + * Creates an unparented callout mapping declaration node owned by this AST. + * The binding kind is set to {@link MethodBindingOperator#KIND_CALLOUT}, + * clients creating a callout override must change this property afterwards. + * + * @return a new unparented callout mapping declaration node + */ + public CalloutMappingDeclaration newCalloutMappingDeclaration() + { + CalloutMappingDeclaration calloutMappingDeclaration = new CalloutMappingDeclaration(this); + calloutMappingDeclaration.bindingOperator().setBindingKind(MethodBindingOperator.KIND_CALLOUT); // default + return calloutMappingDeclaration; + } + + /** + * creates a new unparented method bidning operator node owned by this AST. + * @param keyword one of before/replace/after (callin) or get/set (c-t-f) or null (regular callout) + * @param bindingKind one of {@link MethodBindingOperator#KIND_CALLOUT}, {@link MethodBindingOperator#KIND_CALLOUT_OVERRIDE} or {@link MethodBindingOperator#KIND_CALLIN}. + * @return new unparented node + * @since 1.3.1 + */ + public MethodBindingOperator newMethodBindingOperator(ModifierKeyword keyword, int bindingKind) { + MethodBindingOperator result = new MethodBindingOperator(this); + if (keyword != null) + result.setBindingModifier(newModifier(keyword)); + result.setBindingKind(bindingKind); + return result; + } +//gbr+SH} + +//{ObjectTeams: factory method for MethodSpec + /** + * Creates an unparented method spec declaration node owned by this AST. + * + * @return a new unparented method spec declaration node + */ + public MethodSpec newMethodSpec() + { + return new MethodSpec(this); + } +//gbr} + +// {ObjectTeams: factory method for FieldAccessSpec + /** + * Creates an unparented method spec declaration node owned by this AST. + * + * @return a new unparented method spec declaration node + */ + public FieldAccessSpec newFieldAccessSpec() + { + return new FieldAccessSpec(this); + } +//jsv} + + //=============================== COMMENTS =========================== + + /** + * Creates and returns a new block comment placeholder node. + * <p> + * Note that this node type is used to recording the source + * range where a comment was found in the source string. + * These comment nodes are normally found (only) in + * {@linkplain CompilationUnit#getCommentList() + * the comment table} for parsed compilation units. + * </p> + * + * @return a new unparented block comment node + * @since 3.0 + */ + public BlockComment newBlockComment() { + BlockComment result = new BlockComment(this); + return result; + } + + /** + * Creates and returns a new line comment placeholder node. + * <p> + * Note that this node type is used to recording the source + * range where a comment was found in the source string. + * These comment nodes are normally found (only) in + * {@linkplain CompilationUnit#getCommentList() + * the comment table} for parsed compilation units. + * </p> + * + * @return a new unparented line comment node + * @since 3.0 + */ + public LineComment newLineComment() { + LineComment result = new LineComment(this); + return result; + } + + /** + * Creates and returns a new doc comment node. + * Initially the new node has an empty list of tag elements + * (and, for backwards compatability, an unspecified, but legal, + * doc comment string) + * + * @return a new unparented doc comment node + */ + public Javadoc newJavadoc() { + Javadoc result = new Javadoc(this); + return result; + } + + /** + * Creates and returns a new tag element node. + * Initially the new node has no tag name and an empty list of fragments. + * <p> + * Note that this node type is used only inside doc comments + * ({@link Javadoc}). + * </p> + * + * @return a new unparented tag element node + * @since 3.0 + */ + public TagElement newTagElement() { + TagElement result = new TagElement(this); + return result; + } + + /** + * Creates and returns a new text element node. + * Initially the new node has an empty text string. + * <p> + * Note that this node type is used only inside doc comments + * ({@link Javadoc Javadoc}). + * </p> + * + * @return a new unparented text element node + * @since 3.0 + */ + public TextElement newTextElement() { + TextElement result = new TextElement(this); + return result; + } + + /** + * Creates and returns a new member reference node. + * Initially the new node has no qualifier name and + * an unspecified, but legal, member name. + * <p> + * Note that this node type is used only inside doc comments + * ({@link Javadoc}). + * </p> + * + * @return a new unparented member reference node + * @since 3.0 + */ + public MemberRef newMemberRef() { + MemberRef result = new MemberRef(this); + return result; + } + + /** + * Creates and returns a new method reference node. + * Initially the new node has no qualifier name, + * an unspecified, but legal, method name, and an + * empty parameter list. + * <p> + * Note that this node type is used only inside doc comments + * ({@link Javadoc Javadoc}). + * </p> + * + * @return a new unparented method reference node + * @since 3.0 + */ + public MethodRef newMethodRef() { + MethodRef result = new MethodRef(this); + return result; + } + + /** + * Creates and returns a new method reference node. + * Initially the new node has an unspecified, but legal, + * type, not variable arity, and no parameter name. + * <p> + * Note that this node type is used only inside doc comments + * ({@link Javadoc}). + * </p> + * + * @return a new unparented method reference parameter node + * @since 3.0 + */ + public MethodRefParameter newMethodRefParameter() { + MethodRefParameter result = new MethodRefParameter(this); + return result; + } + + //=============================== STATEMENTS =========================== + /** + * Creates a new unparented local variable declaration statement node + * owned by this AST, for the given variable declaration fragment. + * By default, there are no modifiers and the base type is unspecified + * (but legal). + * <p> + * This method can be used to convert a variable declaration fragment + * (<code>VariableDeclarationFragment</code>) into a statement + * (<code>Statement</code>) by wrapping it. Additional variable + * declaration fragments can be added afterwards. + * </p> + * + * @param fragment the variable declaration fragment + * @return a new unparented variable declaration statement node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * <li>the variable declaration fragment is null</li> + * </ul> + */ + public VariableDeclarationStatement + newVariableDeclarationStatement(VariableDeclarationFragment fragment) { + if (fragment == null) { + throw new IllegalArgumentException(); + } + VariableDeclarationStatement result = + new VariableDeclarationStatement(this); + result.fragments().add(fragment); + return result; + } + + /** + * Creates a new unparented local type declaration statement node + * owned by this AST, for the given type declaration. + * <p> + * This method can be used to convert a type declaration + * (<code>TypeDeclaration</code>) into a statement + * (<code>Statement</code>) by wrapping it. + * </p> + * + * @param decl the type declaration + * @return a new unparented local type declaration statement node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public TypeDeclarationStatement + newTypeDeclarationStatement(TypeDeclaration decl) { + TypeDeclarationStatement result = new TypeDeclarationStatement(this); + result.setDeclaration(decl); + return result; + } + + /** + * Creates a new unparented local type declaration statement node + * owned by this AST, for the given type declaration. + * <p> + * This method can be used to convert any kind of type declaration + * (<code>AbstractTypeDeclaration</code>) into a statement + * (<code>Statement</code>) by wrapping it. + * </p> + * + * @param decl the type declaration + * @return a new unparented local type declaration statement node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + * @since 3.0 + */ + public TypeDeclarationStatement + newTypeDeclarationStatement(AbstractTypeDeclaration decl) { + TypeDeclarationStatement result = new TypeDeclarationStatement(this); + if (this.apiLevel == AST.JLS2) { + result.internalSetTypeDeclaration((TypeDeclaration) decl); + } + if (this.apiLevel >= AST.JLS3) { + result.setDeclaration(decl); + } + return result; + } + + /** + * Creates an unparented block node owned by this AST, for an empty list + * of statements. + * + * @return a new unparented, empty block node + */ + public Block newBlock() { + return new Block(this); + } + + /** + * Creates an unparented continue statement node owned by this AST. + * The continue statement has no label. + * + * @return a new unparented continue statement node + */ + public ContinueStatement newContinueStatement() { + return new ContinueStatement(this); + } + + /** + * Creates an unparented break statement node owned by this AST. + * The break statement has no label. + * + * @return a new unparented break statement node + */ + public BreakStatement newBreakStatement() { + return new BreakStatement(this); + } + + /** + * Creates a new unparented expression statement node owned by this AST, + * for the given expression. + * <p> + * This method can be used to convert an expression + * (<code>Expression</code>) into a statement (<code>Type</code>) + * by wrapping it. Note, however, that the result is only legal for + * limited expression types, including method invocations, assignments, + * and increment/decrement operations. + * </p> + * + * @param expression the expression + * @return a new unparented statement node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public ExpressionStatement newExpressionStatement(Expression expression) { + ExpressionStatement result = new ExpressionStatement(this); + result.setExpression(expression); + return result; + } + + /** + * Creates a new unparented if statement node owned by this AST. + * By default, the expression is unspecified (but legal), + * the then statement is an empty block, and there is no else statement. + * + * @return a new unparented if statement node + */ + public IfStatement newIfStatement() { + return new IfStatement(this); + } + + /** + * Creates a new unparented while statement node owned by this AST. + * By default, the expression is unspecified (but legal), and + * the body statement is an empty block. + * + * @return a new unparented while statement node + */ + public WhileStatement newWhileStatement() { + return new WhileStatement(this); + } + + /** + * Creates a new unparented do statement node owned by this AST. + * By default, the expression is unspecified (but legal), and + * the body statement is an empty block. + * + * @return a new unparented do statement node + */ + public DoStatement newDoStatement() { + return new DoStatement(this); + } + + /** + * Creates a new unparented try statement node owned by this AST. + * By default, the try statement has an empty block, no catch + * clauses, and no finally block. + * + * @return a new unparented try statement node + */ + public TryStatement newTryStatement() { + return new TryStatement(this); + } + + /** + * Creates a new unparented catch clause node owned by this AST. + * By default, the catch clause declares an unspecified, but legal, + * exception declaration and has an empty block. + * + * @return a new unparented catch clause node + */ + public CatchClause newCatchClause() { + return new CatchClause(this); + } + + /** + * Creates a new unparented return statement node owned by this AST. + * By default, the return statement has no expression. + * + * @return a new unparented return statement node + */ + public ReturnStatement newReturnStatement() { + return new ReturnStatement(this); + } + + /** + * Creates a new unparented throw statement node owned by this AST. + * By default, the expression is unspecified, but legal. + * + * @return a new unparented throw statement node + */ + public ThrowStatement newThrowStatement() { + return new ThrowStatement(this); + } + + /** + * Creates a new unparented assert statement node owned by this AST. + * By default, the first expression is unspecified, but legal, and has no + * message expression. + * + * @return a new unparented assert statement node + */ + public AssertStatement newAssertStatement() { + return new AssertStatement(this); + } + + /** + * Creates a new unparented empty statement node owned by this AST. + * + * @return a new unparented empty statement node + */ + public EmptyStatement newEmptyStatement() { + return new EmptyStatement(this); + } + + /** + * Creates a new unparented labeled statement node owned by this AST. + * By default, the label and statement are both unspecified, but legal. + * + * @return a new unparented labeled statement node + */ + public LabeledStatement newLabeledStatement() { + return new LabeledStatement(this); + } + + /** + * Creates a new unparented switch statement node owned by this AST. + * By default, the expression is unspecified, but legal, and there are + * no statements or switch cases. + * + * @return a new unparented labeled statement node + */ + public SwitchStatement newSwitchStatement() { + return new SwitchStatement(this); + } + + /** + * Creates a new unparented switch case statement node owned by + * this AST. By default, the expression is unspecified, but legal. + * + * @return a new unparented switch case node + */ + public SwitchCase newSwitchCase() { + return new SwitchCase(this); + } + + /** + * Creates a new unparented synchronized statement node owned by this AST. + * By default, the expression is unspecified, but legal, and the body is + * an empty block. + * + * @return a new unparented synchronized statement node + */ + public SynchronizedStatement newSynchronizedStatement() { + return new SynchronizedStatement(this); + } + + /** + * Creates a new unparented for statement node owned by this AST. + * By default, there are no initializers, no condition expression, + * no updaters, and the body is an empty block. + * + * @return a new unparented for statement node + */ + public ForStatement newForStatement() { + return new ForStatement(this); + } + + /** + * Creates a new unparented enhanced for statement node owned by this AST. + * By default, the paramter and expression are unspecified + * but legal subtrees, and the body is an empty block. + * + * @return a new unparented throw statement node + * @exception UnsupportedOperationException if this operation is used in + * a JLS2 AST + * @since 3.1 + */ + public EnhancedForStatement newEnhancedForStatement() { + return new EnhancedForStatement(this); + } + +//{ObjectTeams: factory method for WithinStatement + /** + * Creates a new unparented within statement node owned by this AST, + * for an empty list of statements. + * + * @return a new unparented, empty within statement node + * + */ + public WithinStatement newWithinStatement() + { + return new WithinStatement(this); + } +//gbr} + +// {ObjectTeams: factory method for ParameterMapping + /** + * Creates a new unparented parameter mapping node owned by this AST + * + * @return a new unparented, empty parameter mapping node + * + */ + public ParameterMapping newParameterMapping() + { + return new ParameterMapping(this); + } +//jsv} + + //=============================== EXPRESSIONS =========================== + /** + * Creates and returns a new unparented string literal node for + * the empty string literal. + * + * @return a new unparented string literal node + */ + public StringLiteral newStringLiteral() { + return new StringLiteral(this); + } + + + /** + * Creates and returns a new unparented character literal node. + * Initially the node has an unspecified character literal. + * + * @return a new unparented character literal node + */ + public CharacterLiteral newCharacterLiteral() { + return new CharacterLiteral(this); + } + + /** + * Creates and returns a new unparented number literal node. + * + * @param literal the token for the numeric literal as it would + * appear in Java source code + * @return a new unparented number literal node + * @exception IllegalArgumentException if the literal is null + */ + public NumberLiteral newNumberLiteral(String literal) { + if (literal == null) { + throw new IllegalArgumentException(); + } + NumberLiteral result = new NumberLiteral(this); + result.setToken(literal); + return result; + } + + /** + * Creates and returns a new unparented number literal node. + * Initially the number literal token is <code>"0"</code>. + * + * @return a new unparented number literal node + */ + public NumberLiteral newNumberLiteral() { + NumberLiteral result = new NumberLiteral(this); + return result; + } + + /** + * Creates and returns a new unparented null literal node. + * + * @return a new unparented null literal node + */ + public NullLiteral newNullLiteral() { + return new NullLiteral(this); + } + + /** + * Creates and returns a new unparented boolean literal node. + * <p> + * For example, the assignment expression <code>foo = true</code> + * is generated by the following snippet: + * <code> + * <pre> + * Assignment e= ast.newAssignment(); + * e.setLeftHandSide(ast.newSimpleName("foo")); + * e.setRightHandSide(ast.newBooleanLiteral(true)); + * </pre> + * </code> + * </p> + * + * @param value the boolean value + * @return a new unparented boolean literal node + */ + public BooleanLiteral newBooleanLiteral(boolean value) { + BooleanLiteral result = new BooleanLiteral(this); + result.setBooleanValue(value); + return result; + } + + /** + * Creates and returns a new unparented assignment expression node + * owned by this AST. By default, the assignment operator is "=" and + * the left and right hand side expressions are unspecified, but + * legal, names. + * + * @return a new unparented assignment expression node + */ + public Assignment newAssignment() { + Assignment result = new Assignment(this); + return result; + } + + /** + * Creates an unparented method invocation expression node owned by this + * AST. By default, the name of the method is unspecified (but legal) + * there is no receiver expression, no type arguments, and the list of + * arguments is empty. + * + * @return a new unparented method invocation expression node + */ + public MethodInvocation newMethodInvocation() { + MethodInvocation result = new MethodInvocation(this); + return result; + } + + /** + * Creates an unparented "super" method invocation expression node owned by + * this AST. By default, the name of the method is unspecified (but legal) + * there is no qualifier, no type arguments, and the list of arguments is empty. + * + * @return a new unparented "super" method invocation + * expression node + */ + public SuperMethodInvocation newSuperMethodInvocation() { + SuperMethodInvocation result = new SuperMethodInvocation(this); + return result; + } + + /** + * Creates an unparented alternate constructor ("this(...);") invocation + * statement node owned by this AST. By default, the lists of arguments + * and type arguments are both empty. + * <p> + * Note that this type of node is a Statement, whereas a regular + * method invocation is an Expression. The only valid use of these + * statements are as the first statement of a constructor body. + * </p> + * + * @return a new unparented alternate constructor invocation statement node + */ + public ConstructorInvocation newConstructorInvocation() { + ConstructorInvocation result = new ConstructorInvocation(this); + return result; + } + + /** + * Creates an unparented alternate super constructor ("super(...);") + * invocation statement node owned by this AST. By default, there is no + * qualifier, no type arguments, and the list of arguments is empty. + * <p> + * Note that this type of node is a Statement, whereas a regular + * super method invocation is an Expression. The only valid use of these + * statements are as the first statement of a constructor body. + * </p> + * + * @return a new unparented super constructor invocation statement node + */ + public SuperConstructorInvocation newSuperConstructorInvocation() { + SuperConstructorInvocation result = + new SuperConstructorInvocation(this); + return result; + } + + /** + * Creates a new unparented local variable declaration expression node + * owned by this AST, for the given variable declaration fragment. By + * default, there are no modifiers and the base type is unspecified + * (but legal). + * <p> + * This method can be used to convert a variable declaration fragment + * (<code>VariableDeclarationFragment</code>) into an expression + * (<code>Expression</code>) by wrapping it. Additional variable + * declaration fragments can be added afterwards. + * </p> + * + * @param fragment the first variable declaration fragment + * @return a new unparented variable declaration expression node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * <li>the given fragment is null</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public VariableDeclarationExpression + newVariableDeclarationExpression(VariableDeclarationFragment fragment) { + if (fragment == null) { + throw new IllegalArgumentException(); + } + VariableDeclarationExpression result = + new VariableDeclarationExpression(this); + result.fragments().add(fragment); + return result; + } + + /** + * Creates a new unparented field declaration node owned by this AST, + * for the given variable declaration fragment. By default, there are no + * modifiers, no doc comment, and the base type is unspecified + * (but legal). + * <p> + * This method can be used to wrap a variable declaration fragment + * (<code>VariableDeclarationFragment</code>) into a field declaration + * suitable for inclusion in the body of a type declaration + * (<code>FieldDeclaration</code> implements <code>BodyDeclaration</code>). + * Additional variable declaration fragments can be added afterwards. + * </p> + * + * @param fragment the variable declaration fragment + * @return a new unparented field declaration node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * <li>the given fragment is null</li> + * </ul> + */ + public FieldDeclaration newFieldDeclaration(VariableDeclarationFragment fragment) { + if (fragment == null) { + throw new IllegalArgumentException(); + } + FieldDeclaration result = new FieldDeclaration(this); + result.fragments().add(fragment); + return result; + } + + /** + * Creates and returns a new unparented "this" expression node + * owned by this AST. By default, there is no qualifier. + * + * @return a new unparented "this" expression node + */ + public ThisExpression newThisExpression() { + ThisExpression result = new ThisExpression(this); + return result; + } + + /** + * Creates and returns a new unparented field access expression node + * owned by this AST. By default, the expression and field are both + * unspecified, but legal, names. + * + * @return a new unparented field access expression node + */ + public FieldAccess newFieldAccess() { + FieldAccess result = new FieldAccess(this); + return result; + } + + /** + * Creates and returns a new unparented super field access expression node + * owned by this AST. By default, the expression and field are both + * unspecified, but legal, names. + * + * @return a new unparented super field access expression node + */ + public SuperFieldAccess newSuperFieldAccess() { + SuperFieldAccess result = new SuperFieldAccess(this); + return result; + } + + /** + * Creates and returns a new unparented type literal expression node + * owned by this AST. By default, the type is unspecified (but legal). + * + * @return a new unparented type literal node + */ + public TypeLiteral newTypeLiteral() { + TypeLiteral result = new TypeLiteral(this); + return result; + } + + /** + * Creates and returns a new unparented cast expression node + * owned by this AST. By default, the type and expression are unspecified + * (but legal). + * + * @return a new unparented cast expression node + */ + public CastExpression newCastExpression() { + CastExpression result = new CastExpression(this); + return result; + } + + /** + * Creates and returns a new unparented parenthesized expression node + * owned by this AST. By default, the expression is unspecified (but legal). + * + * @return a new unparented parenthesized expression node + */ + public ParenthesizedExpression newParenthesizedExpression() { + ParenthesizedExpression result = new ParenthesizedExpression(this); + return result; + } + + /** + * Creates and returns a new unparented infix expression node + * owned by this AST. By default, the operator and left and right + * operand are unspecified (but legal), and there are no extended + * operands. + * + * @return a new unparented infix expression node + */ + public InfixExpression newInfixExpression() { + InfixExpression result = new InfixExpression(this); + return result; + } + + /** + * Creates and returns a new unparented instanceof expression node + * owned by this AST. By default, the operator and left and right + * operand are unspecified (but legal). + * + * @return a new unparented instanceof expression node + */ + public InstanceofExpression newInstanceofExpression() { + InstanceofExpression result = new InstanceofExpression(this); + return result; + } + + /** + * Creates and returns a new unparented postfix expression node + * owned by this AST. By default, the operator and operand are + * unspecified (but legal). + * + * @return a new unparented postfix expression node + */ + public PostfixExpression newPostfixExpression() { + PostfixExpression result = new PostfixExpression(this); + return result; + } + + /** + * Creates and returns a new unparented prefix expression node + * owned by this AST. By default, the operator and operand are + * unspecified (but legal). + * + * @return a new unparented prefix expression node + */ + public PrefixExpression newPrefixExpression() { + PrefixExpression result = new PrefixExpression(this); + return result; + } + + /** + * Creates and returns a new unparented array access expression node + * owned by this AST. By default, the array and index expression are + * both unspecified (but legal). + * + * @return a new unparented array access expression node + */ + public ArrayAccess newArrayAccess() { + ArrayAccess result = new ArrayAccess(this); + return result; + } + + /** + * Creates and returns a new unparented array creation expression node + * owned by this AST. By default, the array type is an unspecified + * 1-dimensional array, the list of dimensions is empty, and there is no + * array initializer. + * <p> + * Examples: + * <code> + * <pre> + * // new String[len] + * ArrayCreation ac1 = ast.newArrayCreation(); + * ac1.setType( + * ast.newArrayType( + * ast.newSimpleType(ast.newSimpleName("String")))); + * ac1.dimensions().add(ast.newSimpleName("len")); + * + * // new double[7][24][] + * ArrayCreation ac2 = ast.newArrayCreation(); + * ac2.setType( + * ast.newArrayType( + * ast.newPrimitiveType(PrimitiveType.DOUBLE), 3)); + * ac2.dimensions().add(ast.newNumberLiteral("7")); + * ac2.dimensions().add(ast.newNumberLiteral("24")); + * + * // new int[] {1, 2} + * ArrayCreation ac3 = ast.newArrayCreation(); + * ac3.setType( + * ast.newArrayType( + * ast.newPrimitiveType(PrimitiveType.INT))); + * ArrayInitializer ai = ast.newArrayInitializer(); + * ac3.setInitializer(ai); + * ai.expressions().add(ast.newNumberLiteral("1")); + * ai.expressions().add(ast.newNumberLiteral("2")); + * </pre> + * </code> + * </p> + * + * @return a new unparented array creation expression node + */ + public ArrayCreation newArrayCreation() { + ArrayCreation result = new ArrayCreation(this); + return result; + } + + /** + * Creates and returns a new unparented class instance creation + * ("new") expression node owned by this AST. By default, + * there is no qualifying expression, no type parameters, + * an unspecified (but legal) type name, an empty list of + * arguments, and does not declare an anonymous class declaration. + * + * @return a new unparented class instance creation expression node + */ + public ClassInstanceCreation newClassInstanceCreation() { + ClassInstanceCreation result = new ClassInstanceCreation(this); + return result; + } + + /** + * Creates and returns a new unparented anonymous class declaration + * node owned by this AST. By default, the body declaration list is empty. + * + * @return a new unparented anonymous class declaration node + */ + public AnonymousClassDeclaration newAnonymousClassDeclaration() { + AnonymousClassDeclaration result = new AnonymousClassDeclaration(this); + return result; + } + + /** + * Creates and returns a new unparented array initializer node + * owned by this AST. By default, the initializer has no expressions. + * + * @return a new unparented array initializer node + */ + public ArrayInitializer newArrayInitializer() { + ArrayInitializer result = new ArrayInitializer(this); + return result; + } + + /** + * Creates and returns a new unparented conditional expression node + * owned by this AST. By default, the condition and both expressions + * are unspecified (but legal). + * + * @return a new unparented array conditional expression node + */ + public ConditionalExpression newConditionalExpression() { + ConditionalExpression result = new ConditionalExpression(this); + return result; + } + +//{ObjectTeams: factory methods for TSuperMessageSend, BaseConstructorMessageSend, BaseReference, BaseCallMessageSend + /** + * Creates and returns a new unparented "tsuper" expression node + * owned by this AST. By default, there is no qualifier. + * + * @return a new unparented "tsuper" expression node + */ + public TSuperMessageSend newTSuperMessageSend() + { + return new TSuperMessageSend(this); + } + + /** + * Creates and returns a new unparented "tsuper" statement node + * owned by this AST. By default, there is no qualifier. + * + * @return a new unparented "tsuper" expression node + */ + public TSuperConstructorInvocation newTSuperConstructorInvocation() + { + return new TSuperConstructorInvocation(this); + } + + + + /** + * Creates and returns a new unparented "base" callout node + * owned by this AST. + * + * @return a new unparented "base" callout node + */ + public BaseCallMessageSend newBaseCallMessageSend() + { + return new BaseCallMessageSend(this); + } + + + + /** + * Creates and returns a new unparented "base" constructor expression node + * owned by this AST. + * + * @return a new unparented "base" constructor expression node + */ + public BaseConstructorInvocation newBaseConstructorInvocation() + { + return new BaseConstructorInvocation(this); + } +//gbr,mkr} + + //=============================== ANNOTATIONS ==================== + + /** + * Creates and returns a new unparented normal annotation node with + * an unspecified type name and an empty list of member value + * pairs. + * + * @return a new unparented normal annotation node + * @exception UnsupportedOperationException if this operation is used in + * a JLS2 AST + * @since 3.1 + */ + public NormalAnnotation newNormalAnnotation() { + NormalAnnotation result = new NormalAnnotation(this); + return result; + } + + /** + * Creates and returns a new unparented marker annotation node with + * an unspecified type name. + * + * @return a new unparented marker annotation node + * @exception UnsupportedOperationException if this operation is used in + * a JLS2 AST + * @since 3.1 + */ + public MarkerAnnotation newMarkerAnnotation() { + MarkerAnnotation result = new MarkerAnnotation(this); + return result; + } + + /** + * Creates and returns a new unparented single member annotation node with + * an unspecified type name and value. + * + * @return a new unparented single member annotation node + * @exception UnsupportedOperationException if this operation is used in + * a JLS2 AST + * @since 3.1 + */ + public SingleMemberAnnotation newSingleMemberAnnotation() { + SingleMemberAnnotation result = new SingleMemberAnnotation(this); + return result; + } + + /** + * Creates and returns a new unparented member value pair node with + * an unspecified member name and value. + * + * @return a new unparented member value pair node + * @exception UnsupportedOperationException if this operation is used in + * a JLS2 AST + * @since 3.1 + */ + public MemberValuePair newMemberValuePair() { + MemberValuePair result = new MemberValuePair(this); + return result; + } + + /** + * Enables the recording of changes to the given compilation + * unit and its descendents. The compilation unit must have + * been created by <code>ASTParser</code> and still be in + * its original state. Once recording is on, + * arbitrary changes to the subtree rooted at the compilation + * unit are recorded internally. Once the modification has + * been completed, call <code>rewrite</code> to get an object + * representing the corresponding edits to the original + * source code string. + * + * @exception IllegalArgumentException if this compilation unit is + * marked as unmodifiable, or if this compilation unit has already + * been tampered with, or if recording has already been enabled, + * or if <code>root</code> is not owned by this AST + * @see CompilationUnit#recordModifications() + * @since 3.0 + */ + void recordModifications(CompilationUnit root) { + if(this.modificationCount != this.originalModificationCount) { + throw new IllegalArgumentException("AST is already modified"); //$NON-NLS-1$ + } else if(this.rewriter != null) { + throw new IllegalArgumentException("AST modifications are already recorded"); //$NON-NLS-1$ + } else if((root.getFlags() & ASTNode.PROTECT) != 0) { + throw new IllegalArgumentException("Root node is unmodifiable"); //$NON-NLS-1$ + } else if(root.getAST() != this) { + throw new IllegalArgumentException("Root node is not owned by this ast"); //$NON-NLS-1$ + } + + this.rewriter = new InternalASTRewrite(root); + setEventHandler(this.rewriter); + } + + /** + * Converts all modifications recorded into an object + * representing the corresponding text edits to the + * given document containing the original source + * code for the compilation unit that gave rise to + * this AST. + * + * @param document original document containing source code + * for the compilation unit + * @param options the table of formatter options + * (key type: <code>String</code>; value type: <code>String</code>); + * or <code>null</code> to use the standard global options + * {@link JavaCore#getOptions() JavaCore.getOptions()}. + * @return text edit object describing the changes to the + * document corresponding to the recorded AST modifications + * @exception IllegalArgumentException if the document passed is + * <code>null</code> or does not correspond to this AST + * @exception IllegalStateException if <code>recordModifications</code> + * was not called to enable recording + * @see CompilationUnit#rewrite(IDocument, Map) + * @since 3.0 + */ + TextEdit rewrite(IDocument document, Map options) { + if (document == null) { + throw new IllegalArgumentException(); + } + if (this.rewriter == null) { + throw new IllegalStateException("Modifications record is not enabled"); //$NON-NLS-1$ + } + return this.rewriter.rewriteAST(document, options); + } + + /** + * Returns true if the ast tree was created with bindings, false otherwise + * + * @return true if the ast tree was created with bindings, false otherwise + * @since 3.3 + */ + public boolean hasResolvedBindings() { + return (this.bits & RESOLVED_BINDINGS) != 0; + } + + /** + * Returns true if the ast tree was created with statements recovery, false otherwise + * + * @return true if the ast tree was created with statements recovery, false otherwise + * @since 3.3 + */ + public boolean hasStatementsRecovery() { + return (this.bits & ICompilationUnit.ENABLE_STATEMENTS_RECOVERY) != 0; + } + + /** + * Returns true if the ast tree was created with bindings recovery, false otherwise + * + * @return true if the ast tree was created with bindings recovery, false otherwise + * @since 3.3 + */ + public boolean hasBindingsRecovery() { + return (this.bits & ICompilationUnit.ENABLE_BINDINGS_RECOVERY) != 0; + } + + void setFlag(int newValue) { + this.bits |= newValue; + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTConverter.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTConverter.java new file mode 100644 index 000000000..a4ce40dc4 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTConverter.java @@ -0,0 +1,6318 @@ +/******************************************************************************* + * Copyright (c) 2000, 2009 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 + * $Id: ASTConverter.java 23405 2010-02-03 17:02:18Z stephan $ + * + * Contributors: + * IBM Corporation - initial API and implementation + * Fraunhofer FIRST - extended API and implementation + * Technical University Berlin - extended API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.Arrays; +import java.util.Comparator; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.jdt.core.Flags; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.compiler.CategorizedProblem; +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.core.compiler.IProblem; +import org.eclipse.jdt.core.compiler.InvalidInputException; +import org.eclipse.jdt.core.dom.Modifier.ModifierKeyword; +import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; +import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration; +import org.eclipse.jdt.internal.compiler.ast.AllocationExpression; +import org.eclipse.jdt.internal.compiler.ast.Argument; +import org.eclipse.jdt.internal.compiler.ast.FieldReference; +import org.eclipse.jdt.internal.compiler.ast.ForeachStatement; +import org.eclipse.jdt.internal.compiler.ast.JavadocArgumentExpression; +import org.eclipse.jdt.internal.compiler.ast.JavadocFieldReference; +import org.eclipse.jdt.internal.compiler.ast.JavadocMessageSend; +import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; +import org.eclipse.jdt.internal.compiler.ast.MessageSend; +import org.eclipse.jdt.internal.compiler.ast.NameReference; +import org.eclipse.jdt.internal.compiler.ast.OperatorIds; +import org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference; +import org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference; +import org.eclipse.jdt.internal.compiler.ast.QualifiedAllocationExpression; +import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference; +import org.eclipse.jdt.internal.compiler.ast.SingleNameReference; +import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference; +import org.eclipse.jdt.internal.compiler.ast.StringLiteralConcatenation; +import org.eclipse.jdt.internal.compiler.ast.TypeReference; +import org.eclipse.jdt.internal.compiler.ast.Wildcard; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; +import org.eclipse.jdt.internal.compiler.lookup.BlockScope; +import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers; +import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; +import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; +import org.eclipse.jdt.internal.compiler.parser.RecoveryScanner; +import org.eclipse.jdt.internal.compiler.parser.Scanner; +import org.eclipse.jdt.internal.compiler.parser.TerminalTokens; +import org.eclipse.objectteams.otdt.core.compiler.IOTConstants; +import org.eclipse.objectteams.otdt.core.exceptions.InternalCompilerError; +import org.eclipse.objectteams.otdt.internal.core.compiler.ast.AbstractMethodMappingDeclaration; +import org.eclipse.objectteams.otdt.internal.core.compiler.ast.BaseReference; +import org.eclipse.objectteams.otdt.internal.core.compiler.ast.CalloutMappingDeclaration; +import org.eclipse.objectteams.otdt.internal.core.compiler.ast.FieldAccessSpec; +import org.eclipse.objectteams.otdt.internal.core.compiler.ast.LiftingTypeReference; +import org.eclipse.objectteams.otdt.internal.core.compiler.ast.MethodSpec; +import org.eclipse.objectteams.otdt.internal.core.compiler.ast.ParameterMapping; +import org.eclipse.objectteams.otdt.internal.core.compiler.ast.TsuperReference; +import org.eclipse.objectteams.otdt.internal.core.compiler.ast.TypeAnchorReference; +import org.eclipse.objectteams.otdt.internal.core.compiler.ast.WithinStatement; +import org.eclipse.objectteams.otdt.internal.core.compiler.control.ITranslationStates; +import org.eclipse.objectteams.otdt.internal.core.compiler.lifting.Lowering; +import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.RoleTypeBinding; +import org.eclipse.objectteams.otdt.internal.core.compiler.model.RoleModel; +import org.eclipse.objectteams.otdt.internal.core.compiler.statemachine.transformer.MethodSignatureEnhancer; + +/** + * Internal class for converting internal compiler ASTs into public ASTs. + */ +@SuppressWarnings("unchecked") +class ASTConverter { + + protected AST ast; + protected Comment[] commentsTable; + char[] compilationUnitSource; + int compilationUnitSourceLength; + protected DocCommentParser docParser; + // comments + protected boolean insideComments; + protected IProgressMonitor monitor; + protected Set pendingNameScopeResolution; + protected Set pendingThisExpressionScopeResolution; + protected boolean resolveBindings; + Scanner scanner; + private DefaultCommentMapper commentMapper; +//{ObjectTeams: one more configuration option: + private boolean includeRoleFiles= false; +// SH} + + public ASTConverter(Map options, boolean resolveBindings, IProgressMonitor monitor) { + this.resolveBindings = resolveBindings; + Object sourceModeSetting = options.get(JavaCore.COMPILER_SOURCE); + long sourceLevel = CompilerOptions.versionToJdkLevel(sourceModeSetting); + if (sourceLevel == 0) { + // unknown sourceModeSetting + sourceLevel = ClassFileConstants.JDK1_3; + } +//{ObjectTeams: one more configuration option: + Object roleFileOption= options.get(JavaCore.AST_INCLUDES_ROLE_FILES); + if (roleFileOption != null) + includeRoleFiles= JavaCore.ENABLED.equals(roleFileOption); +// SH} + + this.scanner = new Scanner( + true /*comment*/, + false /*whitespace*/, + false /*nls*/, + sourceLevel /*sourceLevel*/, + null /*taskTags*/, + null/*taskPriorities*/, + true/*taskCaseSensitive*/); + this.monitor = monitor; + this.insideComments = JavaCore.ENABLED.equals(options.get(JavaCore.COMPILER_DOC_COMMENT_SUPPORT)); +//{ObjectTeams: initialize scanner mode from options + Object option = options.get(JavaCore.COMPILER_OPT_SCOPED_KEYWORDS); + if (option != null) + this.scanner.parseOTJonly = JavaCore.DISABLED.equals(option); +// SH} + } + + protected void adjustSourcePositionsForParent(org.eclipse.jdt.internal.compiler.ast.Expression expression) { + int start = expression.sourceStart; + int end = expression.sourceEnd; + int leftParentCount = 1; + int rightParentCount = 0; + this.scanner.resetTo(start, end); + try { + int token = this.scanner.getNextToken(); + expression.sourceStart = this.scanner.currentPosition; + boolean stop = false; + while (!stop && ((token = this.scanner.getNextToken()) != TerminalTokens.TokenNameEOF)) { + switch(token) { + case TerminalTokens.TokenNameLPAREN: + leftParentCount++; + break; + case TerminalTokens.TokenNameRPAREN: + rightParentCount++; + if (rightParentCount == leftParentCount) { + // we found the matching parenthesis + stop = true; + } + } + } + expression.sourceEnd = this.scanner.startPosition - 1; + } catch(InvalidInputException e) { + // ignore + } + } + + protected void buildBodyDeclarations(org.eclipse.jdt.internal.compiler.ast.TypeDeclaration typeDeclaration, AbstractTypeDeclaration typeDecl) { + // add body declaration in the lexical order + org.eclipse.jdt.internal.compiler.ast.TypeDeclaration[] members = typeDeclaration.memberTypes; + org.eclipse.jdt.internal.compiler.ast.FieldDeclaration[] fields = typeDeclaration.fields; + org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration[] methods = typeDeclaration.methods; + + int fieldsLength = fields == null? 0 : fields.length; + int methodsLength = methods == null? 0 : methods.length; + int membersLength = members == null ? 0 : members.length; + int fieldsIndex = 0; + int methodsIndex = 0; + int membersIndex = 0; + +//{ObjectTeams: more setup before the loop: + // members were sorted by inheritance, restore lexical order: + if (typeDeclaration.isTeam() && members != null) + Arrays.sort(members, new Comparator<org.eclipse.jdt.internal.compiler.ast.TypeDeclaration>() { + public int compare(org.eclipse.jdt.internal.compiler.ast.TypeDeclaration t1, + org.eclipse.jdt.internal.compiler.ast.TypeDeclaration t2) { + return (t1.sourceStart < t2.sourceStart) ? -1 : 1; + }}); + + // method mapping declarations (callins, callouts) + AbstractMethodMappingDeclaration[] callinCallouts = typeDeclaration.callinCallouts; + int methodMappingsLength = callinCallouts == null ? 0 : callinCallouts.length; + int methodMappingsIndex = 0; +//gbr+SH} + + while ((fieldsIndex < fieldsLength) + || (membersIndex < membersLength) + || (methodsIndex < methodsLength) +//{ObjectTeams + || (methodMappingsIndex < methodMappingsLength)) { +//gbr} + org.eclipse.jdt.internal.compiler.ast.FieldDeclaration nextFieldDeclaration = null; + org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration nextMethodDeclaration = null; + org.eclipse.jdt.internal.compiler.ast.TypeDeclaration nextMemberDeclaration = null; +//{ObjectTeams + org.eclipse.objectteams.otdt.internal.core.compiler.ast.AbstractMethodMappingDeclaration nextMethodMappingDeclaration = null; +//gbr} + + int position = Integer.MAX_VALUE; + int nextDeclarationType = -1; + if (fieldsIndex < fieldsLength) { + nextFieldDeclaration = fields[fieldsIndex]; + if (nextFieldDeclaration.declarationSourceStart < position) { + position = nextFieldDeclaration.declarationSourceStart; + nextDeclarationType = 0; // FIELD + } + } + if (methodsIndex < methodsLength) { + nextMethodDeclaration = methods[methodsIndex]; + if (nextMethodDeclaration.declarationSourceStart < position) { + position = nextMethodDeclaration.declarationSourceStart; + nextDeclarationType = 1; // METHOD + } + } + if (membersIndex < membersLength) { + nextMemberDeclaration = members[membersIndex]; + if (nextMemberDeclaration.declarationSourceStart < position) { + position = nextMemberDeclaration.declarationSourceStart; + nextDeclarationType = 2; // MEMBER + } + } +//{ObjectTeams: case added for method mappings + if (methodMappingsIndex < methodMappingsLength) + { + nextMethodMappingDeclaration = callinCallouts[methodMappingsIndex]; + if (nextMethodMappingDeclaration.sourceStart < position) + { + position = nextMethodMappingDeclaration.sourceStart; + nextDeclarationType = 3; // METHOD_MAPPING + } + } +//gbr} + switch (nextDeclarationType) { + case 0 : + if (nextFieldDeclaration.getKind() == AbstractVariableDeclaration.ENUM_CONSTANT) { + typeDecl.bodyDeclarations().add(convert(nextFieldDeclaration)); + } else { + checkAndAddMultipleFieldDeclaration(fields, fieldsIndex, typeDecl.bodyDeclarations()); + } + fieldsIndex++; + break; + case 1 : + methodsIndex++; +//{ObjectTeams: skip guard predicates which come as methods (are converted via field TypeDeclaration.predicate) + if (nextMethodDeclaration instanceof org.eclipse.objectteams.otdt.internal.core.compiler.ast.GuardPredicateDeclaration) { + break; + } +// SH} + if (!nextMethodDeclaration.isDefaultConstructor() && !nextMethodDeclaration.isClinit() +//{ObjectTeams: ignore generated and copied method declarations + && !nextMethodDeclaration.isGenerated + && !nextMethodDeclaration.isCopied) +//jwl} + { + typeDecl.bodyDeclarations().add(convert(nextMethodDeclaration)); + } +//{ObjectTeams: convert reused abstract method declaration + else if (isReusedAbstractMethodDeclaration(typeDeclaration,nextMethodDeclaration)) + { + typeDecl.bodyDeclarations().add(convertReusedAbstractMethodDeclaration(nextMethodDeclaration)); + } +//jsv} + break; + case 2 : + membersIndex++; +//{ObjectTeams: skip generated members and role files when visited via enclosing team - conditionally: + if ( nextMemberDeclaration.isGenerated + || Flags.isSynthetic(nextMemberDeclaration.modifiers)) + continue; + if (!includeRoleFiles && nextMemberDeclaration.isRoleFile()) + continue; +// SH, jwl} + ASTNode node = convert(nextMemberDeclaration); + if (node == null) { + typeDecl.setFlags(typeDecl.getFlags() | ASTNode.MALFORMED); + } else { + typeDecl.bodyDeclarations().add(node); + } +//{ObjectTeams: case statement added for method mappings + break; + case 3 : + methodMappingsIndex++; + if (nextMethodMappingDeclaration != null) + { + typeDecl.bodyDeclarations().add(convert(nextMethodMappingDeclaration)); + } +//gbr} + } + } + // Convert javadoc + convert(typeDeclaration.javadoc, typeDecl); + } + + protected void buildBodyDeclarations(org.eclipse.jdt.internal.compiler.ast.TypeDeclaration enumDeclaration2, EnumDeclaration enumDeclaration) { + // add body declaration in the lexical order + org.eclipse.jdt.internal.compiler.ast.TypeDeclaration[] members = enumDeclaration2.memberTypes; + org.eclipse.jdt.internal.compiler.ast.FieldDeclaration[] fields = enumDeclaration2.fields; + org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration[] methods = enumDeclaration2.methods; + + int fieldsLength = fields == null? 0 : fields.length; + int methodsLength = methods == null? 0 : methods.length; + int membersLength = members == null ? 0 : members.length; + int fieldsIndex = 0; + int methodsIndex = 0; + int membersIndex = 0; + + while ((fieldsIndex < fieldsLength) + || (membersIndex < membersLength) + || (methodsIndex < methodsLength)) { + org.eclipse.jdt.internal.compiler.ast.FieldDeclaration nextFieldDeclaration = null; + org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration nextMethodDeclaration = null; + org.eclipse.jdt.internal.compiler.ast.TypeDeclaration nextMemberDeclaration = null; + + int position = Integer.MAX_VALUE; + int nextDeclarationType = -1; + if (fieldsIndex < fieldsLength) { + nextFieldDeclaration = fields[fieldsIndex]; + if (nextFieldDeclaration.declarationSourceStart < position) { + position = nextFieldDeclaration.declarationSourceStart; + nextDeclarationType = 0; // FIELD + } + } + if (methodsIndex < methodsLength) { + nextMethodDeclaration = methods[methodsIndex]; + if (nextMethodDeclaration.declarationSourceStart < position) { + position = nextMethodDeclaration.declarationSourceStart; + nextDeclarationType = 1; // METHOD + } + } + if (membersIndex < membersLength) { + nextMemberDeclaration = members[membersIndex]; + if (nextMemberDeclaration.declarationSourceStart < position) { + position = nextMemberDeclaration.declarationSourceStart; + nextDeclarationType = 2; // MEMBER + } + } + switch (nextDeclarationType) { + case 0 : + if (nextFieldDeclaration.getKind() == AbstractVariableDeclaration.ENUM_CONSTANT) { + enumDeclaration.enumConstants().add(convert(nextFieldDeclaration)); + } else { + checkAndAddMultipleFieldDeclaration(fields, fieldsIndex, enumDeclaration.bodyDeclarations()); + } + fieldsIndex++; + break; + case 1 : + methodsIndex++; + if (!nextMethodDeclaration.isDefaultConstructor() && !nextMethodDeclaration.isClinit()) { + enumDeclaration.bodyDeclarations().add(convert(nextMethodDeclaration)); + } + break; + case 2 : + membersIndex++; + enumDeclaration.bodyDeclarations().add(convert(nextMemberDeclaration)); + break; + } + } + convert(enumDeclaration2.javadoc, enumDeclaration); + } + + protected void buildBodyDeclarations(org.eclipse.jdt.internal.compiler.ast.TypeDeclaration expression, AnonymousClassDeclaration anonymousClassDeclaration) { + // add body declaration in the lexical order + org.eclipse.jdt.internal.compiler.ast.TypeDeclaration[] members = expression.memberTypes; + org.eclipse.jdt.internal.compiler.ast.FieldDeclaration[] fields = expression.fields; + org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration[] methods = expression.methods; + + int fieldsLength = fields == null? 0 : fields.length; + int methodsLength = methods == null? 0 : methods.length; + int membersLength = members == null ? 0 : members.length; + int fieldsIndex = 0; + int methodsIndex = 0; + int membersIndex = 0; + + while ((fieldsIndex < fieldsLength) + || (membersIndex < membersLength) + || (methodsIndex < methodsLength)) { + org.eclipse.jdt.internal.compiler.ast.FieldDeclaration nextFieldDeclaration = null; + org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration nextMethodDeclaration = null; + org.eclipse.jdt.internal.compiler.ast.TypeDeclaration nextMemberDeclaration = null; + + int position = Integer.MAX_VALUE; + int nextDeclarationType = -1; + if (fieldsIndex < fieldsLength) { + nextFieldDeclaration = fields[fieldsIndex]; + if (nextFieldDeclaration.declarationSourceStart < position) { + position = nextFieldDeclaration.declarationSourceStart; + nextDeclarationType = 0; // FIELD + } + } + if (methodsIndex < methodsLength) { + nextMethodDeclaration = methods[methodsIndex]; + if (nextMethodDeclaration.declarationSourceStart < position) { + position = nextMethodDeclaration.declarationSourceStart; + nextDeclarationType = 1; // METHOD + } + } + if (membersIndex < membersLength) { + nextMemberDeclaration = members[membersIndex]; + if (nextMemberDeclaration.declarationSourceStart < position) { + position = nextMemberDeclaration.declarationSourceStart; + nextDeclarationType = 2; // MEMBER + } + } + switch (nextDeclarationType) { + case 0 : + if (nextFieldDeclaration.getKind() == AbstractVariableDeclaration.ENUM_CONSTANT) { + anonymousClassDeclaration.bodyDeclarations().add(convert(nextFieldDeclaration)); + } else { + checkAndAddMultipleFieldDeclaration(fields, fieldsIndex, anonymousClassDeclaration.bodyDeclarations()); + } + fieldsIndex++; + break; + case 1 : + methodsIndex++; + if (!nextMethodDeclaration.isDefaultConstructor() && !nextMethodDeclaration.isClinit() +//{ObjectTeams: ignore generated and copied method declarations + && !nextMethodDeclaration.isGenerated + && !nextMethodDeclaration.isCopied) + { +//jwl}) + anonymousClassDeclaration.bodyDeclarations().add(convert(nextMethodDeclaration)); + } +//{ObjectTeams: convert reused abstract method declaration + else if (isReusedAbstractMethodDeclaration(expression, nextMethodDeclaration)) + { + anonymousClassDeclaration.bodyDeclarations().add(convertReusedAbstractMethodDeclaration(nextMethodDeclaration)); + } +//jsv} + break; + case 2 : + membersIndex++; + ASTNode node = convert(nextMemberDeclaration); + if (node == null) { + anonymousClassDeclaration.setFlags(anonymousClassDeclaration.getFlags() | ASTNode.MALFORMED); + } else { +//{ObjectTeams: ignore generated role interfaces + if (!Flags.isSynthetic(nextMemberDeclaration.modifiers)) +// jwl} + + anonymousClassDeclaration.bodyDeclarations().add(node); + } + } + } + } + + /** + * @param compilationUnit + * @param comments + */ + void buildCommentsTable(CompilationUnit compilationUnit, int[][] comments) { + // Build comment table + this.commentsTable = new Comment[comments.length]; + int nbr = 0; + for (int i = 0; i < comments.length; i++) { + Comment comment = createComment(comments[i]); + if (comment != null) { + comment.setAlternateRoot(compilationUnit); + this.commentsTable[nbr++] = comment; + } + } + // Resize table if necessary + if (nbr<comments.length) { + Comment[] newCommentsTable = new Comment[nbr]; + System.arraycopy(this.commentsTable, 0, newCommentsTable, 0, nbr); + this.commentsTable = newCommentsTable; + } + compilationUnit.setCommentTable(this.commentsTable); + } + + protected void checkAndAddMultipleFieldDeclaration(org.eclipse.jdt.internal.compiler.ast.FieldDeclaration[] fields, int index, List bodyDeclarations) { +//{ObjecTeams: ignore generated field declarations + if (Flags.isSynthetic(fields[index].modifiers) || fields[index].copyInheritanceSrc != null) + { + return; + } +//jwl} + if (fields[index] instanceof org.eclipse.jdt.internal.compiler.ast.Initializer) { + org.eclipse.jdt.internal.compiler.ast.Initializer oldInitializer = (org.eclipse.jdt.internal.compiler.ast.Initializer) fields[index]; + Initializer initializer = new Initializer(this.ast); + initializer.setBody(convert(oldInitializer.block)); + setModifiers(initializer, oldInitializer); + initializer.setSourceRange(oldInitializer.declarationSourceStart, oldInitializer.sourceEnd - oldInitializer.declarationSourceStart + 1); + // The javadoc comment is now got from list store in compilation unit declaration + convert(oldInitializer.javadoc, initializer); + bodyDeclarations.add(initializer); + return; + } + if (index > 0 && fields[index - 1].declarationSourceStart == fields[index].declarationSourceStart) { + // we have a multiple field declaration + // We retrieve the existing fieldDeclaration to add the new VariableDeclarationFragment + FieldDeclaration fieldDeclaration = (FieldDeclaration) bodyDeclarations.get(bodyDeclarations.size() - 1); + fieldDeclaration.fragments().add(convertToVariableDeclarationFragment(fields[index])); + } else { + // we can create a new FieldDeclaration + bodyDeclarations.add(convertToFieldDeclaration(fields[index])); + } + } + + protected void checkAndAddMultipleLocalDeclaration(org.eclipse.jdt.internal.compiler.ast.Statement[] stmts, int index, List blockStatements) { + if (index > 0 + && stmts[index - 1] instanceof org.eclipse.jdt.internal.compiler.ast.LocalDeclaration +//{ObjectTeams: ignore generated variable declarations within blocks + && !((org.eclipse.jdt.internal.compiler.ast.LocalDeclaration)stmts[index]).isGenerated) { +//jwl} + org.eclipse.jdt.internal.compiler.ast.LocalDeclaration local1 = (org.eclipse.jdt.internal.compiler.ast.LocalDeclaration) stmts[index - 1]; + org.eclipse.jdt.internal.compiler.ast.LocalDeclaration local2 = (org.eclipse.jdt.internal.compiler.ast.LocalDeclaration) stmts[index]; + if (local1.declarationSourceStart == local2.declarationSourceStart) { + // we have a multiple local declarations + // We retrieve the existing VariableDeclarationStatement to add the new VariableDeclarationFragment + VariableDeclarationStatement variableDeclarationStatement = (VariableDeclarationStatement) blockStatements.get(blockStatements.size() - 1); + variableDeclarationStatement.fragments().add(convertToVariableDeclarationFragment((org.eclipse.jdt.internal.compiler.ast.LocalDeclaration)stmts[index])); + } else { + // we can create a new FieldDeclaration + blockStatements.add(convertToVariableDeclarationStatement((org.eclipse.jdt.internal.compiler.ast.LocalDeclaration)stmts[index])); + } + } else { + // we can create a new FieldDeclaration + blockStatements.add(convertToVariableDeclarationStatement((org.eclipse.jdt.internal.compiler.ast.LocalDeclaration)stmts[index])); + } + } + + protected void checkCanceled() { + if (this.monitor != null && this.monitor.isCanceled()) + throw new OperationCanceledException(); + } + + protected void completeRecord(ArrayType arrayType, org.eclipse.jdt.internal.compiler.ast.ASTNode astNode) { + ArrayType array = arrayType; + int dimensions = array.getDimensions(); + for (int i = 0; i < dimensions; i++) { + Type componentType = array.getComponentType(); + this.recordNodes(componentType, astNode); + if (componentType.isArrayType()) { + array = (ArrayType) componentType; + } + } + } + + public ASTNode convert(org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration methodDeclaration) { + checkCanceled(); + if (methodDeclaration instanceof org.eclipse.jdt.internal.compiler.ast.AnnotationMethodDeclaration) { + return convert((org.eclipse.jdt.internal.compiler.ast.AnnotationMethodDeclaration) methodDeclaration); + } + MethodDeclaration methodDecl = new MethodDeclaration(this.ast); + setModifiers(methodDecl, methodDeclaration); + boolean isConstructor = methodDeclaration.isConstructor(); + methodDecl.setConstructor(isConstructor); + final SimpleName methodName = new SimpleName(this.ast); + methodName.internalSetIdentifier(new String(methodDeclaration.selector)); + int start = methodDeclaration.sourceStart; + int end = retrieveIdentifierEndPosition(start, methodDeclaration.sourceEnd); + methodName.setSourceRange(start, end - start + 1); + methodDecl.setName(methodName); + org.eclipse.jdt.internal.compiler.ast.TypeReference[] thrownExceptions = methodDeclaration.thrownExceptions; + int methodHeaderEnd = methodDeclaration.sourceEnd; + int thrownExceptionsLength = thrownExceptions == null ? 0 : thrownExceptions.length; + if (thrownExceptionsLength > 0) { + Name thrownException; + int i = 0; + do { + thrownException = convert(thrownExceptions[i++]); + methodDecl.thrownExceptions().add(thrownException); + } while (i < thrownExceptionsLength); + methodHeaderEnd = thrownException.getStartPosition() + thrownException.getLength(); + } +//{ObjectTeams: +/* orig: + org.eclipse.jdt.internal.compiler.ast.Argument[] parameters = methodDeclaration.arguments; + :giro */ + org.eclipse.jdt.internal.compiler.ast.Argument[] parameters = MethodSignatureEnhancer.getSourceArguments(methodDeclaration); +// SH} + int parametersLength = parameters == null ? 0 : parameters.length; + if (parametersLength > 0) { + SingleVariableDeclaration parameter; + int i = 0; + do { + parameter = convert(parameters[i++]); + methodDecl.parameters().add(parameter); + } while (i < parametersLength); + if (thrownExceptionsLength == 0) { + methodHeaderEnd = parameter.getStartPosition() + parameter.getLength(); + } + } + org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall explicitConstructorCall = null; + if (isConstructor) { + org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration constructorDeclaration = (org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration) methodDeclaration; + explicitConstructorCall = constructorDeclaration.constructorCall; + switch(this.ast.apiLevel) { + case AST.JLS2_INTERNAL : + // set the return type to VOID + PrimitiveType returnType = new PrimitiveType(this.ast); + returnType.setPrimitiveTypeCode(PrimitiveType.VOID); + returnType.setSourceRange(methodDeclaration.sourceStart, 0); + methodDecl.internalSetReturnType(returnType); + break; + case AST.JLS3 : + methodDecl.setReturnType2(null); + } + } else if (methodDeclaration instanceof org.eclipse.jdt.internal.compiler.ast.MethodDeclaration) { + org.eclipse.jdt.internal.compiler.ast.MethodDeclaration method = (org.eclipse.jdt.internal.compiler.ast.MethodDeclaration) methodDeclaration; + org.eclipse.jdt.internal.compiler.ast.TypeReference typeReference = method.returnType; + if (typeReference != null) { + Type returnType = convertType(typeReference); + // get the positions of the right parenthesis + int rightParenthesisPosition = retrieveEndOfRightParenthesisPosition(end, method.bodyEnd); + int extraDimensions = retrieveExtraDimension(rightParenthesisPosition, method.bodyEnd); + methodDecl.setExtraDimensions(extraDimensions); + setTypeForMethodDeclaration(methodDecl, returnType, extraDimensions); + } else { + switch(this.ast.apiLevel) { + case AST.JLS2_INTERNAL : + methodDecl.setFlags(methodDecl.getFlags() | ASTNode.MALFORMED); + break; + case AST.JLS3 : + methodDecl.setReturnType2(null); + } + } +//{ObjectTeams: + org.eclipse.objectteams.otdt.internal.core.compiler.ast.GuardPredicateDeclaration guard = method.predicate; + if (guard != null) + methodDecl.setGuardPredicate(convertGuardPredicate(guard)); +// SH} + } + int declarationSourceStart = methodDeclaration.declarationSourceStart; + int declarationSourceEnd = methodDeclaration.bodyEnd; +//{ObjectTeams: adjust positions for callout wrappers reusing a source method: + if (declarationSourceEnd < declarationSourceStart) { + assert (methodDeclaration.isCalloutWrapper() && methodDeclaration.isReusingSourceMethod): "should only happen for reused source methods"; //$NON-NLS-1$ + // declarationSourceStart is pointing to the abstract method declaration, + // here we need positions for the generated wrapper which are derived from the callout mapping: + declarationSourceStart= methodDeclaration.bodyStart; + } +// SH} + methodDecl.setSourceRange(declarationSourceStart, declarationSourceEnd - declarationSourceStart + 1); + int closingPosition = retrieveRightBraceOrSemiColonPosition(methodDeclaration.bodyEnd + 1, methodDeclaration.declarationSourceEnd); + if (closingPosition != -1) { + int startPosition = methodDecl.getStartPosition(); + methodDecl.setSourceRange(startPosition, closingPosition - startPosition + 1); + + org.eclipse.jdt.internal.compiler.ast.Statement[] statements = methodDeclaration.statements; + + start = retrieveStartBlockPosition(methodHeaderEnd, methodDeclaration.bodyStart); + if (start == -1) start = methodDeclaration.bodyStart; // use recovery position for body start + end = retrieveRightBrace(methodDeclaration.bodyEnd, methodDeclaration.declarationSourceEnd); + Block block = null; + if (start != -1 && end != -1) { + /* + * start or end can be equal to -1 if we have an interface's method. + */ + block = new Block(this.ast); + block.setSourceRange(start, closingPosition - start + 1); + methodDecl.setBody(block); + } + if (block != null && (statements != null || explicitConstructorCall != null)) { + if (explicitConstructorCall != null && explicitConstructorCall.accessMode != org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall.ImplicitSuper) { + block.statements().add(convert(explicitConstructorCall)); + } + int statementsLength = statements == null ? 0 : statements.length; + for (int i = 0; i < statementsLength; i++) { +//{ObjectTeams: ignore generated local declarations within method declarations + if ((statements[i] instanceof org.eclipse.jdt.internal.compiler.ast.LocalDeclaration) + && ((org.eclipse.jdt.internal.compiler.ast.LocalDeclaration)statements[i]).isGenerated) { + continue; + } +//jwl} + if (statements[i] instanceof org.eclipse.jdt.internal.compiler.ast.LocalDeclaration) { + checkAndAddMultipleLocalDeclaration(statements, i, block.statements()); + } else { + final Statement statement = convert(statements[i]); + if (statement != null) { + block.statements().add(statement); + } + } + } + } + if (block != null && (Modifier.isAbstract(methodDecl.getModifiers()) || Modifier.isNative(methodDecl.getModifiers()))) { + methodDecl.setFlags(methodDecl.getFlags() | ASTNode.MALFORMED); + } + } else { + // syntax error in this method declaration + methodDecl.setFlags(methodDecl.getFlags() | ASTNode.MALFORMED); + if (!methodDeclaration.isNative() && !methodDeclaration.isAbstract()) { + start = retrieveStartBlockPosition(methodHeaderEnd, declarationSourceEnd); + if (start == -1) start = methodDeclaration.bodyStart; // use recovery position for body start + end = methodDeclaration.bodyEnd; + // try to get the best end position + CategorizedProblem[] problems = methodDeclaration.compilationResult().problems; + if (problems != null) { + for (int i = 0, max = methodDeclaration.compilationResult().problemCount; i < max; i++) { + CategorizedProblem currentProblem = problems[i]; + if (currentProblem.getSourceStart() == start && currentProblem.getID() == IProblem.ParsingErrorInsertToComplete) { + end = currentProblem.getSourceEnd(); + break; + } + } + } + int startPosition = methodDecl.getStartPosition(); + methodDecl.setSourceRange(startPosition, end - startPosition + 1); + if (start != -1 && end != -1) { + /* + * start or end can be equal to -1 if we have an interface's method. + */ + Block block = new Block(this.ast); + block.setSourceRange(start, end - start + 1); + methodDecl.setBody(block); + } + } + } + + org.eclipse.jdt.internal.compiler.ast.TypeParameter[] typeParameters = methodDeclaration.typeParameters(); + if (typeParameters != null) { + switch(this.ast.apiLevel) { + case AST.JLS2_INTERNAL : + methodDecl.setFlags(methodDecl.getFlags() | ASTNode.MALFORMED); + break; + case AST.JLS3 : + for (int i = 0, max = typeParameters.length; i < max; i++) { + methodDecl.typeParameters().add(convert(typeParameters[i])); + } + } + } + + // The javadoc comment is now got from list store in compilation unit declaration + convert(methodDeclaration.javadoc, methodDecl); + if (this.resolveBindings) { + recordNodes(methodDecl, methodDeclaration); + recordNodes(methodName, methodDeclaration); + methodDecl.resolveBinding(); + } + return methodDecl; + } + +//{ObjectTeams: convert method for OT-specific internal type AbstractMethodMappingDeclaration + public org.eclipse.jdt.core.dom.AbstractMethodMappingDeclaration convert( + AbstractMethodMappingDeclaration abstractMethodMapping) + { + if (abstractMethodMapping instanceof org.eclipse.objectteams.otdt.internal.core.compiler.ast.CallinMappingDeclaration) + { + return convert((org.eclipse.objectteams.otdt.internal.core.compiler.ast.CallinMappingDeclaration)abstractMethodMapping); + } + if (abstractMethodMapping instanceof org.eclipse.objectteams.otdt.internal.core.compiler.ast.CalloutMappingDeclaration) + { + return convert((org.eclipse.objectteams.otdt.internal.core.compiler.ast.CalloutMappingDeclaration)abstractMethodMapping); + } + throw new IllegalArgumentException("There does not exist a method binding of type" + abstractMethodMapping.getClass()); //$NON-NLS-1$ + } +//gbr} +// {ObjectTeams: convert methods for OT-specific internal types CallinMappingDeclaration +// and CalloutMappingDeclaration + public CallinMappingDeclaration convert( + org.eclipse.objectteams.otdt.internal.core.compiler.ast.CallinMappingDeclaration callinMapping) { + org.eclipse.jdt.core.dom.CallinMappingDeclaration result = this.ast + .newCallinMappingDeclaration(); + + // annotations + setModifiers(result, callinMapping); + + // name + if (callinMapping.hasName()) { + SimpleName labelName = ast.newSimpleName(String.valueOf(callinMapping.name)); + labelName.setSourceRange(callinMapping.sourceStart, callinMapping.sourceEnd - callinMapping.sourceStart + 1); + result.setName(labelName); + } + + // left side, role method + if (callinMapping.roleMethodSpec != null) + result.setRoleMappingElement(convert(callinMapping.roleMethodSpec)); + + // right side, base methods + org.eclipse.objectteams.otdt.internal.core.compiler.ast.MethodSpec[] baseMethodSpecs = callinMapping.baseMethodSpecs; + int len = (baseMethodSpecs != null) ? baseMethodSpecs.length : 0; + for (int idx = 0; idx < len; idx++) { + if (baseMethodSpecs[idx].selector.length > 0) + result.getBaseMappingElements().add(convert(baseMethodSpecs[idx])); + } + org.eclipse.objectteams.otdt.internal.core.compiler.ast.GuardPredicateDeclaration guard = callinMapping.predicate; + if (guard != null) + result.setGuardPredicate(convertGuardPredicate(guard)); + + + // with { ... }, parameter mappings + if (callinMapping.mappings != null) { + int mappingsLength = callinMapping.mappings.length; + for (int idx = 0; idx < mappingsLength; idx++) { + result.getParameterMappings().add( + convert(callinMapping.mappings[idx])); + } + } + + // callin modifier: after, before, replace + ModifierKeyword keyword = null; + int modifierStart = callinMapping.modifierStart; + int modifierLength = callinMapping.modifierEnd- modifierStart + 1; + switch (callinMapping.callinModifier) { + case TerminalTokens.TokenNamebefore: + keyword = ModifierKeyword.BEFORE_KEYWORD; + break; + case TerminalTokens.TokenNameafter: + keyword = ModifierKeyword.AFTER_KEYWORD; + break; + case TerminalTokens.TokenNamereplace: + keyword = ModifierKeyword.REPLACE_KEYWORD; + break; + default: + keyword = ModifierKeyword.MISSING_KEYWORD; + modifierStart= retrieveBINDINPosition(callinMapping.sourceEnd, callinMapping.declarationSourceEnd); + if (modifierStart == -1) + modifierStart= callinMapping.baseDeclarationSourceStart()-1; + else + modifierStart += 2; // skip "<-" + modifierLength= 0; + break; + } + MethodBindingOperator bindingOperator = this.ast.newMethodBindingOperator(keyword, MethodBindingOperator.KIND_CALLIN); + bindingOperator.setSourceRange(callinMapping.bindingTokenStart, callinMapping.modifierEnd-callinMapping.bindingTokenStart+1); + bindingOperator.bindingModifier().setSourceRange(modifierStart, modifierLength); + result.setBindingOperator(bindingOperator); + + result.setSourceRange(callinMapping.declarationSourceStart, + callinMapping.declarationSourceEnd - callinMapping.declarationSourceStart + 1); + + convert(callinMapping.javadoc, result); + + if (this.resolveBindings) { + this.recordNodes(result, callinMapping); + } + return result; + } + + public org.eclipse.jdt.core.dom.CalloutMappingDeclaration convert( + CalloutMappingDeclaration calloutMapping) + { + org.eclipse.jdt.core.dom.CalloutMappingDeclaration result = this.ast + .newCalloutMappingDeclaration(); + + // annotations + setModifiers(result, calloutMapping); + + org.eclipse.objectteams.otdt.internal.core.compiler.ast.MethodSpec roleMethodSpec = calloutMapping.roleMethodSpec; + if (roleMethodSpec != null) { + org.eclipse.jdt.core.dom.MethodMappingElement leftMethodSpec = convert(roleMethodSpec); + result.setRoleMappingElement(leftMethodSpec); + } + // possible types for calloutMapping.baseMethodSpec: MethodSpec, + // FieldAccesSpec + if (calloutMapping.baseMethodSpec != null && calloutMapping.baseMethodSpec.selector.length > 0) { + result.setBaseMappingElement(convert(calloutMapping.baseMethodSpec)); + if (calloutMapping.isCalloutToField()) { + FieldAccessSpec fieldAccessSpec = (FieldAccessSpec)calloutMapping.baseMethodSpec; + result.bindingOperator().setBindingModifier(fieldAccessSpec.isSetter() ? Modifier.OT_SET_CALLOUT : Modifier.OT_GET_CALLOUT); + } + } else { + result.setBaseMappingElement(null); // mark as initialized + } + + // convert parameter mappings + if (calloutMapping.mappings != null) { + for (int idx = 0; idx < calloutMapping.mappings.length; idx++) { + result.getParameterMappings().add(idx, + convert(calloutMapping.mappings[idx])); + } + } + + result.setSourceRange(calloutMapping.declarationSourceStart, + calloutMapping.declarationSourceEnd - calloutMapping.declarationSourceStart + 1); + + convert(calloutMapping.javadoc, result); + + if (this.resolveBindings) { + this.recordNodes(result, calloutMapping); + result.resolveBinding(); + } + result.setSignatureFlag(calloutMapping.hasSignature); + + // binding operator (kind and modifier) + ModifierKeyword keyword = null; + int modifierStart = calloutMapping.modifierStart; + int modifierLength = calloutMapping.modifierEnd - modifierStart + 1; + if (calloutMapping.baseMethodSpec instanceof FieldAccessSpec) { + if (((FieldAccessSpec)calloutMapping.baseMethodSpec).isSetter()) + keyword = ModifierKeyword.SET_KEYWORD; + else + keyword = ModifierKeyword.GET_KEYWORD; + } + int calloutKind = calloutMapping.isCalloutOverride() ? MethodBindingOperator.KIND_CALLOUT_OVERRIDE : MethodBindingOperator.KIND_CALLOUT; + + MethodBindingOperator bindingOperator = this.ast.newMethodBindingOperator(keyword, calloutKind); + bindingOperator.setSourceRange(calloutMapping.bindingTokenStart, calloutMapping.modifierEnd-calloutMapping.bindingTokenStart+1); + if (keyword != null) + bindingOperator.bindingModifier().setSourceRange(modifierStart, modifierLength); + result.setBindingOperator(bindingOperator); + + return result; + } +//gbr} + +//{ObjectTeams: convert method for OT-specific internal type ParameterMapping + @SuppressWarnings("nls") + public org.eclipse.jdt.core.dom.ParameterMapping convert( + ParameterMapping parameterMapping) { + org.eclipse.jdt.core.dom.ParameterMapping result = this.ast + .newParameterMapping(); + + result + .setSourceRange( + parameterMapping.sourceStart, + (parameterMapping.sourceEnd - parameterMapping.sourceStart) + 1); + + result.setExpression(convert(parameterMapping.expression)); + + if (parameterMapping.direction == TerminalTokens.TokenNameBINDIN) + result.setDirection("<-"); + + if (parameterMapping.direction == TerminalTokens.TokenNameBINDOUT) + result.setDirection("->"); + + result.setIdentifier(convert(parameterMapping.ident)); + + if (new String(parameterMapping.ident.token).equals("result")) + result.setResultFlag(true); + else + result.setResultFlag(false); + + return result; + } + + // jsv} + +// {ObjectTeams: convert method for OT-specific internal type + // ParameterMapping + public org.eclipse.jdt.core.dom.FieldAccessSpec convert( + FieldAccessSpec fieldAccessSpec) { + org.eclipse.jdt.core.dom.FieldAccessSpec result = this.ast + .newFieldAccessSpec(); + + result.setSourceRange(fieldAccessSpec.declarationSourceStart, + fieldAccessSpec.declarationSourceEnd - fieldAccessSpec.declarationSourceStart + 1); + + result.setSignatureFlag(fieldAccessSpec.hasSignature); + + String[] tokens = (new String(fieldAccessSpec.selector)).split("\\" //$NON-NLS-1$ + + IOTConstants.JAVA_SEPARATOR); + String realName = tokens[tokens.length - 1]; + SimpleName fieldName = this.ast.newSimpleName(realName); + int start = fieldAccessSpec.sourceStart; + int end = retrieveEndOfElementTypeNamePosition(start, + fieldAccessSpec.sourceEnd); + fieldName.setSourceRange(start, end - start + 1); + result.setName(fieldName); + + org.eclipse.jdt.internal.compiler.ast.TypeReference typeReference = fieldAccessSpec.declaredType(); + if (typeReference != null) { + Type fieldType = convertType(typeReference); + result.setFieldType(fieldType); + } + + if (this.resolveBindings) { + recordNodes(result, fieldAccessSpec); + recordNodes(fieldName, fieldAccessSpec); + } + + return result; + } + + // jsv} + +// {ObjectTeams: convert method for OT-specific internal type + // MethodMappingElement + public MethodMappingElement convert(MethodSpec methodSpec) { + if (methodSpec instanceof org.eclipse.objectteams.otdt.internal.core.compiler.ast.FieldAccessSpec) { + return convert((org.eclipse.objectteams.otdt.internal.core.compiler.ast.FieldAccessSpec) methodSpec); + } + + org.eclipse.jdt.core.dom.MethodSpec result = this.ast.newMethodSpec(); + + SimpleName methodName = this.ast.newSimpleName(new String(methodSpec.selector)); + int start = methodSpec.sourceStart; + int end = retrieveEndOfElementTypeNamePosition(start, methodSpec.sourceEnd); + methodName.setSourceRange(start, end - start + 1); + result.setName(methodName); + + if (methodSpec.hasSignature) { + org.eclipse.jdt.internal.compiler.ast.TypeReference typeReference = methodSpec.returnType; + if (typeReference != null) { + Type returnType = convertType(typeReference); + if(result.getAST().apiLevel() == AST.JLS3) + result.setReturnType2(returnType); + else + result.setReturnType(returnType); + } + + org.eclipse.jdt.internal.compiler.ast.Argument[] parameters = methodSpec.arguments; + if (parameters != null) { + int parametersLength = parameters.length; + for (int idx = 0; idx < parametersLength; idx++) { + result.parameters().add(convert(parameters[idx])); + } + } + + org.eclipse.jdt.internal.compiler.ast.TypeParameter[] typeParameters = methodSpec.typeParameters; + if (typeParameters != null) + if (this.ast.apiLevel == AST.JLS3) + for (int i = 0, max = typeParameters.length; i < max; i++) + result.typeParameters().add(convert(typeParameters[i])); + } + + result.setSourceRange(methodSpec.declarationSourceStart, + methodSpec.declarationSourceEnd + - methodSpec.declarationSourceStart + 1); + + result.setSignatureFlag(methodSpec.hasSignature); + result.setCovariantReturnFlag(methodSpec.covariantReturn); + + if (this.resolveBindings) { + recordNodes(result, methodSpec); + recordNodes(methodName, methodSpec); + } + + return result; + } +//gbr} + + + public ClassInstanceCreation convert(org.eclipse.jdt.internal.compiler.ast.AllocationExpression expression) { + ClassInstanceCreation classInstanceCreation = new ClassInstanceCreation(this.ast); + if (this.resolveBindings) { + recordNodes(classInstanceCreation, expression); + } + if (expression.typeArguments != null) { + switch(this.ast.apiLevel) { + case AST.JLS2_INTERNAL : + classInstanceCreation.setFlags(classInstanceCreation.getFlags() | ASTNode.MALFORMED); + break; + case AST.JLS3 : + for (int i = 0, max = expression.typeArguments.length; i < max; i++) { + classInstanceCreation.typeArguments().add(convertType(expression.typeArguments[i])); + } + } + } + switch(this.ast.apiLevel) { + case AST.JLS2_INTERNAL : + classInstanceCreation.internalSetName(convert(expression.type)); + break; + case AST.JLS3 : + classInstanceCreation.setType(convertType(expression.type)); + } + classInstanceCreation.setSourceRange(expression.sourceStart, expression.sourceEnd - expression.sourceStart + 1); + org.eclipse.jdt.internal.compiler.ast.Expression[] arguments = expression.arguments; + if (arguments != null) { + int length = arguments.length; + for (int i = 0; i < length; i++) { + classInstanceCreation.arguments().add(convert(arguments[i])); + } + } + removeTrailingCommentFromExpressionEndingWithAParen(classInstanceCreation); + return classInstanceCreation; + } + + public Expression convert(org.eclipse.jdt.internal.compiler.ast.AND_AND_Expression expression) { + InfixExpression infixExpression = new InfixExpression(this.ast); + infixExpression.setOperator(InfixExpression.Operator.CONDITIONAL_AND); + if (this.resolveBindings) { + this.recordNodes(infixExpression, expression); + } + final int expressionOperatorID = (expression.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.OperatorMASK) >> org.eclipse.jdt.internal.compiler.ast.ASTNode.OperatorSHIFT; + if (expression.left instanceof org.eclipse.jdt.internal.compiler.ast.BinaryExpression + && ((expression.left.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.ParenthesizedMASK) == 0)) { + // create an extended string literal equivalent => use the extended operands list + infixExpression.extendedOperands().add(convert(expression.right)); + org.eclipse.jdt.internal.compiler.ast.Expression leftOperand = expression.left; + org.eclipse.jdt.internal.compiler.ast.Expression rightOperand = null; + do { + rightOperand = ((org.eclipse.jdt.internal.compiler.ast.BinaryExpression) leftOperand).right; + if ((((leftOperand.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.OperatorMASK) >> org.eclipse.jdt.internal.compiler.ast.ASTNode.OperatorSHIFT) != expressionOperatorID + && ((leftOperand.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.ParenthesizedMASK) == 0)) + || ((rightOperand instanceof org.eclipse.jdt.internal.compiler.ast.BinaryExpression + && ((rightOperand.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.OperatorMASK) >> org.eclipse.jdt.internal.compiler.ast.ASTNode.OperatorSHIFT) != expressionOperatorID) + && ((rightOperand.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.ParenthesizedMASK) == 0))) { + List extendedOperands = infixExpression.extendedOperands(); + InfixExpression temp = new InfixExpression(this.ast); + if (this.resolveBindings) { + this.recordNodes(temp, expression); + } + temp.setOperator(getOperatorFor(expressionOperatorID)); + Expression leftSide = convert(leftOperand); + temp.setLeftOperand(leftSide); + temp.setSourceRange(leftSide.getStartPosition(), leftSide.getLength()); + int size = extendedOperands.size(); + for (int i = 0; i < size - 1; i++) { + Expression expr = temp; + temp = new InfixExpression(this.ast); + + if (this.resolveBindings) { + this.recordNodes(temp, expression); + } + temp.setLeftOperand(expr); + temp.setOperator(getOperatorFor(expressionOperatorID)); + temp.setSourceRange(expr.getStartPosition(), expr.getLength()); + } + infixExpression = temp; + for (int i = 0; i < size; i++) { + Expression extendedOperand = (Expression) extendedOperands.remove(size - 1 - i); + temp.setRightOperand(extendedOperand); + int startPosition = temp.getLeftOperand().getStartPosition(); + temp.setSourceRange(startPosition, extendedOperand.getStartPosition() + extendedOperand.getLength() - startPosition); + if (temp.getLeftOperand().getNodeType() == ASTNode.INFIX_EXPRESSION) { + temp = (InfixExpression) temp.getLeftOperand(); + } + } + int startPosition = infixExpression.getLeftOperand().getStartPosition(); + infixExpression.setSourceRange(startPosition, expression.sourceEnd - startPosition + 1); + if (this.resolveBindings) { + this.recordNodes(infixExpression, expression); + } + return infixExpression; + } + infixExpression.extendedOperands().add(0, convert(rightOperand)); + leftOperand = ((org.eclipse.jdt.internal.compiler.ast.BinaryExpression) leftOperand).left; + } while (leftOperand instanceof org.eclipse.jdt.internal.compiler.ast.BinaryExpression && ((leftOperand.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.ParenthesizedMASK) == 0)); + Expression leftExpression = convert(leftOperand); + infixExpression.setLeftOperand(leftExpression); + infixExpression.setRightOperand((Expression)infixExpression.extendedOperands().remove(0)); + int startPosition = leftExpression.getStartPosition(); + infixExpression.setSourceRange(startPosition, expression.sourceEnd - startPosition + 1); + return infixExpression; + } + Expression leftExpression = convert(expression.left); + infixExpression.setLeftOperand(leftExpression); + infixExpression.setRightOperand(convert(expression.right)); + infixExpression.setOperator(InfixExpression.Operator.CONDITIONAL_AND); + int startPosition = leftExpression.getStartPosition(); + infixExpression.setSourceRange(startPosition, expression.sourceEnd - startPosition + 1); + return infixExpression; + } + + private AnnotationTypeDeclaration convertToAnnotationDeclaration(org.eclipse.jdt.internal.compiler.ast.TypeDeclaration typeDeclaration) { + checkCanceled(); + if (this.scanner.sourceLevel < ClassFileConstants.JDK1_5) return null; + AnnotationTypeDeclaration typeDecl = this.ast.newAnnotationTypeDeclaration(); + setModifiers(typeDecl, typeDeclaration); + final SimpleName typeName = new SimpleName(this.ast); + typeName.internalSetIdentifier(new String(typeDeclaration.name)); + typeName.setSourceRange(typeDeclaration.sourceStart, typeDeclaration.sourceEnd - typeDeclaration.sourceStart + 1); + typeDecl.setName(typeName); + typeDecl.setSourceRange(typeDeclaration.declarationSourceStart, typeDeclaration.bodyEnd - typeDeclaration.declarationSourceStart + 1); + + buildBodyDeclarations(typeDeclaration, typeDecl); + // The javadoc comment is now got from list store in compilation unit declaration + if (this.resolveBindings) { + recordNodes(typeDecl, typeDeclaration); + recordNodes(typeName, typeDeclaration); + typeDecl.resolveBinding(); + } + return typeDecl; + } + + public ASTNode convert(org.eclipse.jdt.internal.compiler.ast.AnnotationMethodDeclaration annotationTypeMemberDeclaration) { + checkCanceled(); + if (this.ast.apiLevel == AST.JLS2_INTERNAL) { + return null; + } + AnnotationTypeMemberDeclaration annotationTypeMemberDeclaration2 = new AnnotationTypeMemberDeclaration(this.ast); + setModifiers(annotationTypeMemberDeclaration2, annotationTypeMemberDeclaration); + final SimpleName methodName = new SimpleName(this.ast); + methodName.internalSetIdentifier(new String(annotationTypeMemberDeclaration.selector)); + int start = annotationTypeMemberDeclaration.sourceStart; + int end = retrieveIdentifierEndPosition(start, annotationTypeMemberDeclaration.sourceEnd); + methodName.setSourceRange(start, end - start + 1); + annotationTypeMemberDeclaration2.setName(methodName); + org.eclipse.jdt.internal.compiler.ast.TypeReference typeReference = annotationTypeMemberDeclaration.returnType; + if (typeReference != null) { + Type returnType = convertType(typeReference); + setTypeForMethodDeclaration(annotationTypeMemberDeclaration2, returnType, 0); + } + int declarationSourceStart = annotationTypeMemberDeclaration.declarationSourceStart; + int declarationSourceEnd = annotationTypeMemberDeclaration.bodyEnd; + annotationTypeMemberDeclaration2.setSourceRange(declarationSourceStart, declarationSourceEnd - declarationSourceStart + 1); + // The javadoc comment is now got from list store in compilation unit declaration + convert(annotationTypeMemberDeclaration.javadoc, annotationTypeMemberDeclaration2); + org.eclipse.jdt.internal.compiler.ast.Expression memberValue = annotationTypeMemberDeclaration.defaultValue; + if (memberValue != null) { + annotationTypeMemberDeclaration2.setDefault(convert(memberValue)); + } + if (this.resolveBindings) { + recordNodes(annotationTypeMemberDeclaration2, annotationTypeMemberDeclaration); + recordNodes(methodName, annotationTypeMemberDeclaration); + annotationTypeMemberDeclaration2.resolveBinding(); + } + return annotationTypeMemberDeclaration2; + } + + public SingleVariableDeclaration convert(org.eclipse.jdt.internal.compiler.ast.Argument argument) { + SingleVariableDeclaration variableDecl = new SingleVariableDeclaration(this.ast); + setModifiers(variableDecl, argument); +//{ObjectTeams: we have to check the variable name e.g. in a LiftingType + String[] tokens = (new String(argument.name)).split("\\"+IOTConstants.JAVA_SEPARATOR); //$NON-NLS-1$ + String realName = tokens[tokens.length-1]; + final SimpleName name = new SimpleName(this.ast); + name.internalSetIdentifier(realName); +/* orig: + name.internalSetIdentifier(new String(argument.name)); + :giro */ +//jsv} Original: + int start = argument.sourceStart; + int nameEnd = argument.sourceEnd; + name.setSourceRange(start, nameEnd - start + 1); + variableDecl.setName(name); + final int typeSourceEnd = argument.type.sourceEnd; + final int extraDimensions = retrieveExtraDimension(nameEnd + 1, typeSourceEnd); + variableDecl.setExtraDimensions(extraDimensions); + final boolean isVarArgs = argument.isVarArgs(); + if (isVarArgs && extraDimensions == 0) { + // remove the ellipsis from the type source end + argument.type.sourceEnd = retrieveEllipsisStartPosition(argument.type.sourceStart, typeSourceEnd); + } + Type type = convertType(argument.type); + int typeEnd = type.getStartPosition() + type.getLength() - 1; + int rightEnd = Math.max(typeEnd, argument.declarationSourceEnd); + /* + * There is extra work to do to set the proper type positions + * See PR http://bugs.eclipse.org/bugs/show_bug.cgi?id=23284 + */ + if (isVarArgs) { + setTypeForSingleVariableDeclaration(variableDecl, type, extraDimensions + 1); + if (extraDimensions != 0) { + variableDecl.setFlags(variableDecl.getFlags() | ASTNode.MALFORMED); + } + } else { + setTypeForSingleVariableDeclaration(variableDecl, type, extraDimensions); + } + variableDecl.setSourceRange(argument.declarationSourceStart, rightEnd - argument.declarationSourceStart + 1); + + if (isVarArgs) { + switch(this.ast.apiLevel) { + case AST.JLS2_INTERNAL : + variableDecl.setFlags(variableDecl.getFlags() | ASTNode.MALFORMED); + break; + case AST.JLS3 : + variableDecl.setVarargs(true); + } + } + if (this.resolveBindings) { + recordNodes(name, argument); + recordNodes(variableDecl, argument); + variableDecl.resolveBinding(); + } + return variableDecl; + } + + + public Annotation convert(org.eclipse.jdt.internal.compiler.ast.Annotation annotation) { + if (annotation instanceof org.eclipse.jdt.internal.compiler.ast.SingleMemberAnnotation) { + return convert((org.eclipse.jdt.internal.compiler.ast.SingleMemberAnnotation) annotation); + } else if (annotation instanceof org.eclipse.jdt.internal.compiler.ast.MarkerAnnotation) { + return convert((org.eclipse.jdt.internal.compiler.ast.MarkerAnnotation) annotation); + } else { + return convert((org.eclipse.jdt.internal.compiler.ast.NormalAnnotation) annotation); + } + } + + public ArrayCreation convert(org.eclipse.jdt.internal.compiler.ast.ArrayAllocationExpression expression) { + ArrayCreation arrayCreation = new ArrayCreation(this.ast); + if (this.resolveBindings) { + recordNodes(arrayCreation, expression); + } + arrayCreation.setSourceRange(expression.sourceStart, expression.sourceEnd - expression.sourceStart + 1); + org.eclipse.jdt.internal.compiler.ast.Expression[] dimensions = expression.dimensions; + + int dimensionsLength = dimensions.length; + for (int i = 0; i < dimensionsLength; i++) { + if (dimensions[i] != null) { + Expression dimension = convert(dimensions[i]); + if (this.resolveBindings) { + recordNodes(dimension, dimensions[i]); + } + arrayCreation.dimensions().add(dimension); + } + } + Type type = convertType(expression.type); + if (this.resolveBindings) { + recordNodes(type, expression.type); + } + ArrayType arrayType = null; + if (type.isArrayType()) { + arrayType = (ArrayType) type; + } else { + arrayType = this.ast.newArrayType(type, dimensionsLength); + if (this.resolveBindings) { + completeRecord(arrayType, expression); + } + int start = type.getStartPosition(); + int end = type.getStartPosition() + type.getLength(); + int previousSearchStart = end - 1; + ArrayType componentType = (ArrayType) type.getParent(); + for (int i = 0; i < dimensionsLength; i++) { + previousSearchStart = retrieveRightBracketPosition(previousSearchStart + 1, this.compilationUnitSourceLength); + componentType.setSourceRange(start, previousSearchStart - start + 1); + componentType = (ArrayType) componentType.getParent(); + } + } + arrayCreation.setType(arrayType); + if (this.resolveBindings) { + recordNodes(arrayType, expression); + } + if (expression.initializer != null) { + arrayCreation.setInitializer(convert(expression.initializer)); + } + return arrayCreation; + } + + public ArrayInitializer convert(org.eclipse.jdt.internal.compiler.ast.ArrayInitializer expression) { + ArrayInitializer arrayInitializer = new ArrayInitializer(this.ast); + if (this.resolveBindings) { + recordNodes(arrayInitializer, expression); + } + arrayInitializer.setSourceRange(expression.sourceStart, expression.sourceEnd - expression.sourceStart + 1); + org.eclipse.jdt.internal.compiler.ast.Expression[] expressions = expression.expressions; + if (expressions != null) { + int length = expressions.length; + for (int i = 0; i < length; i++) { + Expression expr = convert(expressions[i]); + if (this.resolveBindings) { + recordNodes(expr, expressions[i]); + } + arrayInitializer.expressions().add(expr); + } + } + return arrayInitializer; + } + + public ArrayAccess convert(org.eclipse.jdt.internal.compiler.ast.ArrayReference reference) { + ArrayAccess arrayAccess = new ArrayAccess(this.ast); + if (this.resolveBindings) { + recordNodes(arrayAccess, reference); + } + arrayAccess.setSourceRange(reference.sourceStart, reference.sourceEnd - reference.sourceStart + 1); + arrayAccess.setArray(convert(reference.receiver)); + arrayAccess.setIndex(convert(reference.position)); + return arrayAccess; + } + + public AssertStatement convert(org.eclipse.jdt.internal.compiler.ast.AssertStatement statement) { + AssertStatement assertStatement = new AssertStatement(this.ast); + final Expression assertExpression = convert(statement.assertExpression); + Expression searchingNode = assertExpression; + assertStatement.setExpression(assertExpression); + org.eclipse.jdt.internal.compiler.ast.Expression exceptionArgument = statement.exceptionArgument; + if (exceptionArgument != null) { + final Expression exceptionMessage = convert(exceptionArgument); + assertStatement.setMessage(exceptionMessage); + searchingNode = exceptionMessage; + } + int start = statement.sourceStart; + int sourceEnd = retrieveSemiColonPosition(searchingNode); + if (sourceEnd == -1) { + sourceEnd = searchingNode.getStartPosition() + searchingNode.getLength() - 1; + assertStatement.setSourceRange(start, sourceEnd - start + 1); + } else { + assertStatement.setSourceRange(start, sourceEnd - start + 1); + } + return assertStatement; + } + + public Assignment convert(org.eclipse.jdt.internal.compiler.ast.Assignment expression) { + Assignment assignment = new Assignment(this.ast); + if (this.resolveBindings) { + recordNodes(assignment, expression); + } + Expression lhs = convert(expression.lhs); + assignment.setLeftHandSide(lhs); + assignment.setOperator(Assignment.Operator.ASSIGN); + assignment.setRightHandSide(convert(expression.expression)); + int start = lhs.getStartPosition(); + assignment.setSourceRange(start, expression.sourceEnd - start + 1); + return assignment; + } + + /* + * Internal use only + * Used to convert class body declarations + */ + public TypeDeclaration convert(org.eclipse.jdt.internal.compiler.ast.ASTNode[] nodes) { + final TypeDeclaration typeDecl = new TypeDeclaration(this.ast); + typeDecl.setInterface(false); + int nodesLength = nodes.length; + for (int i = 0; i < nodesLength; i++) { + org.eclipse.jdt.internal.compiler.ast.ASTNode node = nodes[i]; + if (node instanceof org.eclipse.jdt.internal.compiler.ast.Initializer) { + org.eclipse.jdt.internal.compiler.ast.Initializer oldInitializer = (org.eclipse.jdt.internal.compiler.ast.Initializer) node; + Initializer initializer = new Initializer(this.ast); + initializer.setBody(convert(oldInitializer.block)); + setModifiers(initializer, oldInitializer); + initializer.setSourceRange(oldInitializer.declarationSourceStart, oldInitializer.sourceEnd - oldInitializer.declarationSourceStart + 1); +// setJavaDocComment(initializer); +// initializer.setJavadoc(convert(oldInitializer.javadoc)); + convert(oldInitializer.javadoc, initializer); + typeDecl.bodyDeclarations().add(initializer); + } else if (node instanceof org.eclipse.jdt.internal.compiler.ast.FieldDeclaration) { + org.eclipse.jdt.internal.compiler.ast.FieldDeclaration fieldDeclaration = (org.eclipse.jdt.internal.compiler.ast.FieldDeclaration) node; + if (i > 0 + && (nodes[i - 1] instanceof org.eclipse.jdt.internal.compiler.ast.FieldDeclaration) + && ((org.eclipse.jdt.internal.compiler.ast.FieldDeclaration)nodes[i - 1]).declarationSourceStart == fieldDeclaration.declarationSourceStart) { + // we have a multiple field declaration + // We retrieve the existing fieldDeclaration to add the new VariableDeclarationFragment + FieldDeclaration currentFieldDeclaration = (FieldDeclaration) typeDecl.bodyDeclarations().get(typeDecl.bodyDeclarations().size() - 1); + currentFieldDeclaration.fragments().add(convertToVariableDeclarationFragment(fieldDeclaration)); + } else { + // we can create a new FieldDeclaration + typeDecl.bodyDeclarations().add(convertToFieldDeclaration(fieldDeclaration)); + } + } else if(node instanceof org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration) { + AbstractMethodDeclaration nextMethodDeclaration = (AbstractMethodDeclaration) node; + if (!nextMethodDeclaration.isDefaultConstructor() && !nextMethodDeclaration.isClinit()) { +//{ObjectTeams: ignore generated and copied method declarations + if (!nextMethodDeclaration.isGenerated && !nextMethodDeclaration.isCopied) +//jwl} + typeDecl.bodyDeclarations().add(convert(nextMethodDeclaration)); + } + } else if(node instanceof org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) { + org.eclipse.jdt.internal.compiler.ast.TypeDeclaration nextMemberDeclaration = (org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) node; + ASTNode nextMemberDeclarationNode = convert(nextMemberDeclaration); + if (nextMemberDeclarationNode == null) { + typeDecl.setFlags(typeDecl.getFlags() | ASTNode.MALFORMED); + } else { +//{ObjectTeams: ignore generated role interfaces + if (!Flags.isSynthetic(nextMemberDeclaration.modifiers)) +// jwl} + typeDecl.bodyDeclarations().add(nextMemberDeclarationNode); + } + } + } + return typeDecl; + } + + public Expression convert(org.eclipse.jdt.internal.compiler.ast.BinaryExpression expression) { + InfixExpression infixExpression = new InfixExpression(this.ast); + if (this.resolveBindings) { + this.recordNodes(infixExpression, expression); + } + + int expressionOperatorID = (expression.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.OperatorMASK) >> org.eclipse.jdt.internal.compiler.ast.ASTNode.OperatorSHIFT; + switch (expressionOperatorID) { + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.EQUAL_EQUAL : + infixExpression.setOperator(InfixExpression.Operator.EQUALS); + break; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.LESS_EQUAL : + infixExpression.setOperator(InfixExpression.Operator.LESS_EQUALS); + break; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.GREATER_EQUAL : + infixExpression.setOperator(InfixExpression.Operator.GREATER_EQUALS); + break; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.NOT_EQUAL : + infixExpression.setOperator(InfixExpression.Operator.NOT_EQUALS); + break; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.LEFT_SHIFT : + infixExpression.setOperator(InfixExpression.Operator.LEFT_SHIFT); + break; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.RIGHT_SHIFT : + infixExpression.setOperator(InfixExpression.Operator.RIGHT_SHIFT_SIGNED); + break; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.UNSIGNED_RIGHT_SHIFT : + infixExpression.setOperator(InfixExpression.Operator.RIGHT_SHIFT_UNSIGNED); + break; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.OR_OR : + infixExpression.setOperator(InfixExpression.Operator.CONDITIONAL_OR); + break; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.AND_AND : + infixExpression.setOperator(InfixExpression.Operator.CONDITIONAL_AND); + break; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.PLUS : + infixExpression.setOperator(InfixExpression.Operator.PLUS); + break; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.MINUS : + infixExpression.setOperator(InfixExpression.Operator.MINUS); + break; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.REMAINDER : + infixExpression.setOperator(InfixExpression.Operator.REMAINDER); + break; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.XOR : + infixExpression.setOperator(InfixExpression.Operator.XOR); + break; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.AND : + infixExpression.setOperator(InfixExpression.Operator.AND); + break; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.MULTIPLY : + infixExpression.setOperator(InfixExpression.Operator.TIMES); + break; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.OR : + infixExpression.setOperator(InfixExpression.Operator.OR); + break; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.DIVIDE : + infixExpression.setOperator(InfixExpression.Operator.DIVIDE); + break; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.GREATER : + infixExpression.setOperator(InfixExpression.Operator.GREATER); + break; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.LESS : + infixExpression.setOperator(InfixExpression.Operator.LESS); + } + + if (expression.left instanceof org.eclipse.jdt.internal.compiler.ast.BinaryExpression + && ((expression.left.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.ParenthesizedMASK) == 0)) { + // create an extended string literal equivalent => use the extended operands list + infixExpression.extendedOperands().add(convert(expression.right)); + org.eclipse.jdt.internal.compiler.ast.Expression leftOperand = expression.left; + org.eclipse.jdt.internal.compiler.ast.Expression rightOperand = null; + do { + rightOperand = ((org.eclipse.jdt.internal.compiler.ast.BinaryExpression) leftOperand).right; + if ((((leftOperand.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.OperatorMASK) >> org.eclipse.jdt.internal.compiler.ast.ASTNode.OperatorSHIFT) != expressionOperatorID + && ((leftOperand.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.ParenthesizedMASK) == 0)) + || ((rightOperand instanceof org.eclipse.jdt.internal.compiler.ast.BinaryExpression + && ((rightOperand.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.OperatorMASK) >> org.eclipse.jdt.internal.compiler.ast.ASTNode.OperatorSHIFT) != expressionOperatorID) + && ((rightOperand.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.ParenthesizedMASK) == 0))) { + List extendedOperands = infixExpression.extendedOperands(); + InfixExpression temp = new InfixExpression(this.ast); + if (this.resolveBindings) { + this.recordNodes(temp, expression); + } + temp.setOperator(getOperatorFor(expressionOperatorID)); + Expression leftSide = convert(leftOperand); + temp.setLeftOperand(leftSide); + temp.setSourceRange(leftSide.getStartPosition(), leftSide.getLength()); + int size = extendedOperands.size(); + for (int i = 0; i < size - 1; i++) { + Expression expr = temp; + temp = new InfixExpression(this.ast); + + if (this.resolveBindings) { + this.recordNodes(temp, expression); + } + temp.setLeftOperand(expr); + temp.setOperator(getOperatorFor(expressionOperatorID)); + temp.setSourceRange(expr.getStartPosition(), expr.getLength()); + } + infixExpression = temp; + for (int i = 0; i < size; i++) { + Expression extendedOperand = (Expression) extendedOperands.remove(size - 1 - i); + temp.setRightOperand(extendedOperand); + int startPosition = temp.getLeftOperand().getStartPosition(); + temp.setSourceRange(startPosition, extendedOperand.getStartPosition() + extendedOperand.getLength() - startPosition); + if (temp.getLeftOperand().getNodeType() == ASTNode.INFIX_EXPRESSION) { + temp = (InfixExpression) temp.getLeftOperand(); + } + } + int startPosition = infixExpression.getLeftOperand().getStartPosition(); + infixExpression.setSourceRange(startPosition, expression.sourceEnd - startPosition + 1); + if (this.resolveBindings) { + this.recordNodes(infixExpression, expression); + } + return infixExpression; + } + infixExpression.extendedOperands().add(0, convert(rightOperand)); + leftOperand = ((org.eclipse.jdt.internal.compiler.ast.BinaryExpression) leftOperand).left; + } while (leftOperand instanceof org.eclipse.jdt.internal.compiler.ast.BinaryExpression && ((leftOperand.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.ParenthesizedMASK) == 0)); + Expression leftExpression = convert(leftOperand); + infixExpression.setLeftOperand(leftExpression); + infixExpression.setRightOperand((Expression)infixExpression.extendedOperands().remove(0)); + int startPosition = leftExpression.getStartPosition(); + infixExpression.setSourceRange(startPosition, expression.sourceEnd - startPosition + 1); + return infixExpression; + } else if (expression.left instanceof StringLiteralConcatenation + && ((expression.left.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.ParenthesizedMASK) == 0) + && (OperatorIds.PLUS == expressionOperatorID)) { + StringLiteralConcatenation literal = (StringLiteralConcatenation) expression.left; + final org.eclipse.jdt.internal.compiler.ast.Expression[] stringLiterals = literal.literals; + infixExpression.setLeftOperand(convert(stringLiterals[0])); + infixExpression.setRightOperand(convert(stringLiterals[1])); + for (int i = 2; i < literal.counter; i++) { + infixExpression.extendedOperands().add(convert(stringLiterals[i])); + } + infixExpression.extendedOperands().add(convert(expression.right)); + int startPosition = literal.sourceStart; + infixExpression.setSourceRange(startPosition, expression.sourceEnd - startPosition + 1); + return infixExpression; + } + Expression leftExpression = convert(expression.left); + infixExpression.setLeftOperand(leftExpression); + infixExpression.setRightOperand(convert(expression.right)); + int startPosition = leftExpression.getStartPosition(); + infixExpression.setSourceRange(startPosition, expression.sourceEnd - startPosition + 1); + return infixExpression; + } + + public Block convert(org.eclipse.jdt.internal.compiler.ast.Block statement) { + Block block = new Block(this.ast); + if (statement.sourceEnd > 0) { + block.setSourceRange(statement.sourceStart, statement.sourceEnd - statement.sourceStart + 1); + } + org.eclipse.jdt.internal.compiler.ast.Statement[] statements = statement.statements; + if (statements != null) { + int statementsLength = statements.length; + for (int i = 0; i < statementsLength; i++) { + if (statements[i] instanceof org.eclipse.jdt.internal.compiler.ast.LocalDeclaration +//{ObjectTeams: ignore generated local declarations within blocs + && !((org.eclipse.jdt.internal.compiler.ast.LocalDeclaration)statements[i]).isGenerated) { +//jwl} + checkAndAddMultipleLocalDeclaration(statements, i, block.statements()); + } else { + Statement statement2 = convert(statements[i]); + if (statement2 != null) { + block.statements().add(statement2); + } + } + } + } + return block; + } + +// {ObjectTeams: convert method for OT-specific internal type WithinStatement + /** + * Converts internal compiler type WithinStatement to dom type WithinStatement. + * The first two _OT$ Elements (for team activation) are left out. The body is + * recovered from the try block, e.g. + * <code> + * within(new SimpleTeam()) + * { + * foo(); + * } + * </code> + * will be in the internal compiler ast + * <code> + * org.objectteams.Team _OT$team$206 = new SimpleTeam(); + * ... + * int _OT$level206 = _OT$team$206.activate(3); + * try + * { + * foo(); + * } + * finally + * { + * _OT$team$206.deactivate(_OT$level206); + * } + * </code> + */ + public org.eclipse.jdt.core.dom.WithinStatement convert(WithinStatement statement) + { + org.eclipse.jdt.core.dom.WithinStatement result = this.ast.newWithinStatement(); + + if (statement.sourceEnd > 0) + { + result.setSourceRange(statement.sourceStart, statement.sourceEnd - statement.sourceStart + 1); + } + + result.setTeamExpression(convert(statement.getTeamExpression())); + + org.eclipse.jdt.internal.compiler.ast.Statement[] statements = statement.statements; + if (statements != null) + { + // for within statements use statements inside try block + for (int idx = 0; idx < statements.length; idx++) { + if (statements[idx] instanceof org.eclipse.jdt.internal.compiler.ast.TryStatement) + { + org.eclipse.jdt.internal.compiler.ast.TryStatement tryStatement = + (org.eclipse.jdt.internal.compiler.ast.TryStatement)statements[idx]; + Block tryBlock = convert(tryStatement.tryBlock); + tryBlock.setParent(null, null); + result.setBody(tryBlock); + break; + } + } + } + + return result; + } +//mkr} + + + public BreakStatement convert(org.eclipse.jdt.internal.compiler.ast.BreakStatement statement) { + BreakStatement breakStatement = new BreakStatement(this.ast); + breakStatement.setSourceRange(statement.sourceStart, statement.sourceEnd - statement.sourceStart + 1); + if (statement.label != null) { + final SimpleName name = new SimpleName(this.ast); + name.internalSetIdentifier(new String(statement.label)); + retrieveIdentifierAndSetPositions(statement.sourceStart, statement.sourceEnd, name); + breakStatement.setLabel(name); + } + return breakStatement; + } + + + public SwitchCase convert(org.eclipse.jdt.internal.compiler.ast.CaseStatement statement) { + SwitchCase switchCase = new SwitchCase(this.ast); + org.eclipse.jdt.internal.compiler.ast.Expression constantExpression = statement.constantExpression; + if (constantExpression == null) { + switchCase.setExpression(null); + } else { + switchCase.setExpression(convert(constantExpression)); + } + switchCase.setSourceRange(statement.sourceStart, statement.sourceEnd - statement.sourceStart + 1); + retrieveColonPosition(switchCase); + return switchCase; + } + + public CastExpression convert(org.eclipse.jdt.internal.compiler.ast.CastExpression expression) { + CastExpression castExpression = new CastExpression(this.ast); + castExpression.setSourceRange(expression.sourceStart, expression.sourceEnd - expression.sourceStart + 1); + org.eclipse.jdt.internal.compiler.ast.Expression type = expression.type; + trimWhiteSpacesAndComments(type); + if (type instanceof org.eclipse.jdt.internal.compiler.ast.TypeReference ) { + castExpression.setType(convertType((org.eclipse.jdt.internal.compiler.ast.TypeReference)type)); + } else if (type instanceof org.eclipse.jdt.internal.compiler.ast.NameReference) { + castExpression.setType(convertToType((org.eclipse.jdt.internal.compiler.ast.NameReference)type)); + } + castExpression.setExpression(convert(expression.expression)); + if (this.resolveBindings) { + recordNodes(castExpression, expression); + } + return castExpression; + } + + public CharacterLiteral convert(org.eclipse.jdt.internal.compiler.ast.CharLiteral expression) { + int length = expression.sourceEnd - expression.sourceStart + 1; + int sourceStart = expression.sourceStart; + CharacterLiteral literal = new CharacterLiteral(this.ast); + if (this.resolveBindings) { + this.recordNodes(literal, expression); + } + literal.internalSetEscapedValue(new String(this.compilationUnitSource, sourceStart, length)); + literal.setSourceRange(sourceStart, length); + removeLeadingAndTrailingCommentsFromLiteral(literal); + return literal; + } + public Expression convert(org.eclipse.jdt.internal.compiler.ast.ClassLiteralAccess expression) { + TypeLiteral typeLiteral = new TypeLiteral(this.ast); + if (this.resolveBindings) { + this.recordNodes(typeLiteral, expression); + } + typeLiteral.setSourceRange(expression.sourceStart, expression.sourceEnd - expression.sourceStart + 1); + typeLiteral.setType(convertType(expression.type)); + return typeLiteral; + } + + public CompilationUnit convert(org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration unit, char[] source) { + if(unit.compilationResult.recoveryScannerData != null) { + RecoveryScanner recoveryScanner = new RecoveryScanner(this.scanner, unit.compilationResult.recoveryScannerData.removeUnused()); + this.scanner = recoveryScanner; + this.docParser.scanner = this.scanner; + } + this.compilationUnitSource = source; + this.compilationUnitSourceLength = source.length; + this.scanner.setSource(source, unit.compilationResult); + CompilationUnit compilationUnit = new CompilationUnit(this.ast); + compilationUnit.setStatementsRecoveryData(unit.compilationResult.recoveryScannerData); + + // Parse comments + int[][] comments = unit.comments; + if (comments != null) { + buildCommentsTable(compilationUnit, comments); + } + + // handle the package declaration immediately + // There is no node corresponding to the package declaration + if (this.resolveBindings) { + recordNodes(compilationUnit, unit); + } + if (unit.currentPackage != null) { + PackageDeclaration packageDeclaration = convertPackage(unit); + compilationUnit.setPackage(packageDeclaration); + } + org.eclipse.jdt.internal.compiler.ast.ImportReference[] imports = unit.imports; + if (imports != null) { + int importLength = imports.length; + for (int i = 0; i < importLength; i++) { + compilationUnit.imports().add(convertImport(imports[i])); + } + } + + org.eclipse.jdt.internal.compiler.ast.TypeDeclaration[] types = unit.types; + if (types != null) { + int typesLength = types.length; + for (int i = 0; i < typesLength; i++) { + org.eclipse.jdt.internal.compiler.ast.TypeDeclaration declaration = types[i]; + if (CharOperation.equals(declaration.name, TypeConstants.PACKAGE_INFO_NAME)) { + continue; + } + ASTNode type = convert(declaration); + if (type == null) { + compilationUnit.setFlags(compilationUnit.getFlags() | ASTNode.MALFORMED); + } else { +//{ObjectTeams: ignore generated role interfaces + if (!Flags.isSynthetic(types[i].modifiers)) +// jwl} + + compilationUnit.types().add(type); + } + } + } + compilationUnit.setSourceRange(unit.sourceStart, unit.sourceEnd - unit.sourceStart + 1); + + int problemLength = unit.compilationResult.problemCount; + if (problemLength != 0) { + CategorizedProblem[] resizedProblems = null; + final CategorizedProblem[] problems = unit.compilationResult.getProblems(); + final int realProblemLength=problems.length; + if (realProblemLength == problemLength) { + resizedProblems = problems; + } else { + System.arraycopy(problems, 0, (resizedProblems = new CategorizedProblem[realProblemLength]), 0, realProblemLength); + } + ASTSyntaxErrorPropagator syntaxErrorPropagator = new ASTSyntaxErrorPropagator(resizedProblems); + compilationUnit.accept(syntaxErrorPropagator); + ASTRecoveryPropagator recoveryPropagator = + new ASTRecoveryPropagator(resizedProblems, unit.compilationResult.recoveryScannerData); + compilationUnit.accept(recoveryPropagator); + compilationUnit.setProblems(resizedProblems); + } + if (this.resolveBindings) { + lookupForScopes(); + } + compilationUnit.initCommentMapper(this.scanner); + return compilationUnit; + } + + public Assignment convert(org.eclipse.jdt.internal.compiler.ast.CompoundAssignment expression) { + Assignment assignment = new Assignment(this.ast); + Expression lhs = convert(expression.lhs); + assignment.setLeftHandSide(lhs); + int start = lhs.getStartPosition(); + assignment.setSourceRange(start, expression.sourceEnd - start + 1); + switch (expression.operator) { + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.PLUS : + assignment.setOperator(Assignment.Operator.PLUS_ASSIGN); + break; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.MINUS : + assignment.setOperator(Assignment.Operator.MINUS_ASSIGN); + break; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.MULTIPLY : + assignment.setOperator(Assignment.Operator.TIMES_ASSIGN); + break; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.DIVIDE : + assignment.setOperator(Assignment.Operator.DIVIDE_ASSIGN); + break; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.AND : + assignment.setOperator(Assignment.Operator.BIT_AND_ASSIGN); + break; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.OR : + assignment.setOperator(Assignment.Operator.BIT_OR_ASSIGN); + break; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.XOR : + assignment.setOperator(Assignment.Operator.BIT_XOR_ASSIGN); + break; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.REMAINDER : + assignment.setOperator(Assignment.Operator.REMAINDER_ASSIGN); + break; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.LEFT_SHIFT : + assignment.setOperator(Assignment.Operator.LEFT_SHIFT_ASSIGN); + break; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.RIGHT_SHIFT : + assignment.setOperator(Assignment.Operator.RIGHT_SHIFT_SIGNED_ASSIGN); + break; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.UNSIGNED_RIGHT_SHIFT : + assignment.setOperator(Assignment.Operator.RIGHT_SHIFT_UNSIGNED_ASSIGN); + break; + } + assignment.setRightHandSide(convert(expression.expression)); + if (this.resolveBindings) { + recordNodes(assignment, expression); + } + return assignment; + } + + public ConditionalExpression convert(org.eclipse.jdt.internal.compiler.ast.ConditionalExpression expression) { + ConditionalExpression conditionalExpression = new ConditionalExpression(this.ast); + if (this.resolveBindings) { + recordNodes(conditionalExpression, expression); + } + conditionalExpression.setSourceRange(expression.sourceStart, expression.sourceEnd - expression.sourceStart + 1); + conditionalExpression.setExpression(convert(expression.condition)); + conditionalExpression.setThenExpression(convert(expression.valueIfTrue)); + conditionalExpression.setElseExpression(convert(expression.valueIfFalse)); + return conditionalExpression; + } + + public ContinueStatement convert(org.eclipse.jdt.internal.compiler.ast.ContinueStatement statement) { + ContinueStatement continueStatement = new ContinueStatement(this.ast); + continueStatement.setSourceRange(statement.sourceStart, statement.sourceEnd - statement.sourceStart + 1); + if (statement.label != null) { + final SimpleName name = new SimpleName(this.ast); + name.internalSetIdentifier(new String(statement.label)); + retrieveIdentifierAndSetPositions(statement.sourceStart, statement.sourceEnd, name); + continueStatement.setLabel(name); + } + return continueStatement; + } + + public DoStatement convert(org.eclipse.jdt.internal.compiler.ast.DoStatement statement) { + DoStatement doStatement = new DoStatement(this.ast); + doStatement.setSourceRange(statement.sourceStart, statement.sourceEnd - statement.sourceStart + 1); + doStatement.setExpression(convert(statement.condition)); + final Statement action = convert(statement.action); + if (action == null) return null; + doStatement.setBody(action); + return doStatement; + } + + public NumberLiteral convert(org.eclipse.jdt.internal.compiler.ast.DoubleLiteral expression) { + int length = expression.sourceEnd - expression.sourceStart + 1; + int sourceStart = expression.sourceStart; + NumberLiteral literal = new NumberLiteral(this.ast); + literal.internalSetToken(new String(this.compilationUnitSource, sourceStart, length)); + if (this.resolveBindings) { + this.recordNodes(literal, expression); + } + literal.setSourceRange(sourceStart, length); + removeLeadingAndTrailingCommentsFromLiteral(literal); + return literal; + } + + public EmptyStatement convert(org.eclipse.jdt.internal.compiler.ast.EmptyStatement statement) { + EmptyStatement emptyStatement = new EmptyStatement(this.ast); + emptyStatement.setSourceRange(statement.sourceStart, statement.sourceEnd - statement.sourceStart + 1); + return emptyStatement; + } + + // field is an enum constant + public EnumConstantDeclaration convert(org.eclipse.jdt.internal.compiler.ast.FieldDeclaration enumConstant) { + checkCanceled(); + EnumConstantDeclaration enumConstantDeclaration = new EnumConstantDeclaration(this.ast); + final SimpleName typeName = new SimpleName(this.ast); + typeName.internalSetIdentifier(new String(enumConstant.name)); + typeName.setSourceRange(enumConstant.sourceStart, enumConstant.sourceEnd - enumConstant.sourceStart + 1); + enumConstantDeclaration.setName(typeName); + int declarationSourceStart = enumConstant.declarationSourceStart; + int declarationSourceEnd = enumConstant.declarationSourceEnd; + final org.eclipse.jdt.internal.compiler.ast.Expression initialization = enumConstant.initialization; + + if (initialization != null) { + + if (initialization instanceof QualifiedAllocationExpression) { + org.eclipse.jdt.internal.compiler.ast.TypeDeclaration anonymousType = ((QualifiedAllocationExpression) initialization).anonymousType; + if (anonymousType != null) { + AnonymousClassDeclaration anonymousClassDeclaration = new AnonymousClassDeclaration(this.ast); + int start = retrieveStartBlockPosition(anonymousType.sourceEnd, anonymousType.bodyEnd); + int end = retrieveRightBrace(anonymousType.bodyEnd, declarationSourceEnd); + if (end == -1) end = anonymousType.bodyEnd; + anonymousClassDeclaration.setSourceRange(start, end - start + 1); + enumConstantDeclaration.setAnonymousClassDeclaration(anonymousClassDeclaration); + buildBodyDeclarations(anonymousType, anonymousClassDeclaration); + if (this.resolveBindings) { + recordNodes(anonymousClassDeclaration, anonymousType); + anonymousClassDeclaration.resolveBinding(); + } + enumConstantDeclaration.setSourceRange(declarationSourceStart, end - declarationSourceStart + 1); + } + } else { + enumConstantDeclaration.setSourceRange(declarationSourceStart, declarationSourceEnd - declarationSourceStart + 1); + } + final org.eclipse.jdt.internal.compiler.ast.Expression[] arguments = ((org.eclipse.jdt.internal.compiler.ast.AllocationExpression) initialization).arguments; + + if (arguments != null) { + for (int i = 0, max = arguments.length; i < max; i++) { + enumConstantDeclaration.arguments().add(convert(arguments[i])); + } + } + } else { + enumConstantDeclaration.setSourceRange(declarationSourceStart, declarationSourceEnd - declarationSourceStart + 1); + } + setModifiers(enumConstantDeclaration, enumConstant); + if (this.resolveBindings) { + recordNodes(enumConstantDeclaration, enumConstant); + recordNodes(typeName, enumConstant); + enumConstantDeclaration.resolveVariable(); + } + convert(enumConstant.javadoc, enumConstantDeclaration); + return enumConstantDeclaration; + } + + public Expression convert(org.eclipse.jdt.internal.compiler.ast.EqualExpression expression) { + InfixExpression infixExpression = new InfixExpression(this.ast); + if (this.resolveBindings) { + recordNodes(infixExpression, expression); + } + Expression leftExpression = convert(expression.left); + infixExpression.setLeftOperand(leftExpression); + infixExpression.setRightOperand(convert(expression.right)); + int startPosition = leftExpression.getStartPosition(); + infixExpression.setSourceRange(startPosition, expression.sourceEnd - startPosition + 1); + switch ((expression.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.OperatorMASK) >> org.eclipse.jdt.internal.compiler.ast.ASTNode.OperatorSHIFT) { + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.EQUAL_EQUAL : + infixExpression.setOperator(InfixExpression.Operator.EQUALS); + break; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.NOT_EQUAL : + infixExpression.setOperator(InfixExpression.Operator.NOT_EQUALS); + } + return infixExpression; + + } + + public Statement convert(org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall statement) { + Statement newStatement; + int sourceStart = statement.sourceStart; +//{ObjectTeams: convert tsuper constructor invocation + if (statement.isTsuperAccess()) + { + TSuperConstructorInvocation result = this.ast.newTSuperConstructorInvocation(); + org.eclipse.jdt.internal.compiler.ast.Expression[] arguments = statement.arguments; + if (arguments != null) + { + int length = arguments.length; + length--; // remove last marker argument + for (int i = 0; i < length; i++) + { + result.getArguments().add(convert(arguments[i])); + } + } + newStatement = result; + } else +//mkr} + if (statement.isSuperAccess() || statement.isSuper()) { + SuperConstructorInvocation superConstructorInvocation = new SuperConstructorInvocation(this.ast); + if (statement.qualification != null) { + superConstructorInvocation.setExpression(convert(statement.qualification)); + } + org.eclipse.jdt.internal.compiler.ast.Expression[] arguments = statement.arguments; + if (arguments != null) { + int length = arguments.length; + for (int i = 0; i < length; i++) { + superConstructorInvocation.arguments().add(convert(arguments[i])); + } + } + if (statement.typeArguments != null) { + if (sourceStart > statement.typeArgumentsSourceStart) { + sourceStart = statement.typeArgumentsSourceStart; + } + switch(this.ast.apiLevel) { + case AST.JLS2_INTERNAL : + superConstructorInvocation.setFlags(superConstructorInvocation.getFlags() | ASTNode.MALFORMED); + break; + case AST.JLS3 : + for (int i = 0, max = statement.typeArguments.length; i < max; i++) { + superConstructorInvocation.typeArguments().add(convertType(statement.typeArguments[i])); + } + break; + } + } + newStatement = superConstructorInvocation; + } else { + ConstructorInvocation constructorInvocation = new ConstructorInvocation(this.ast); + org.eclipse.jdt.internal.compiler.ast.Expression[] arguments = statement.arguments; + if (arguments != null) { + int length = arguments.length; + for (int i = 0; i < length; i++) { + constructorInvocation.arguments().add(convert(arguments[i])); + } + } + if (statement.typeArguments != null) { + if (sourceStart > statement.typeArgumentsSourceStart) { + sourceStart = statement.typeArgumentsSourceStart; + } + switch(this.ast.apiLevel) { + case AST.JLS2_INTERNAL : + constructorInvocation.setFlags(constructorInvocation.getFlags() | ASTNode.MALFORMED); + break; + case AST.JLS3 : + for (int i = 0, max = statement.typeArguments.length; i < max; i++) { + constructorInvocation.typeArguments().add(convertType(statement.typeArguments[i])); + } + break; + } + } + if (statement.qualification != null) { + // this is an error + constructorInvocation.setFlags(constructorInvocation.getFlags() | ASTNode.MALFORMED); + } + newStatement = constructorInvocation; + } + newStatement.setSourceRange(sourceStart, statement.sourceEnd - sourceStart + 1); + if (this.resolveBindings) { + recordNodes(newStatement, statement); + } + return newStatement; + } + + public Expression convert(org.eclipse.jdt.internal.compiler.ast.Expression expression) { + if ((expression.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.ParenthesizedMASK) != 0) { + return convertToParenthesizedExpression(expression); + } + if (expression instanceof org.eclipse.jdt.internal.compiler.ast.Annotation) { + return convert((org.eclipse.jdt.internal.compiler.ast.Annotation) expression); + } + if (expression instanceof org.eclipse.jdt.internal.compiler.ast.CastExpression) { + return convert((org.eclipse.jdt.internal.compiler.ast.CastExpression) expression); + } + // switch between all types of expression + if (expression instanceof org.eclipse.jdt.internal.compiler.ast.ArrayAllocationExpression) { + return convert((org.eclipse.jdt.internal.compiler.ast.ArrayAllocationExpression) expression); + } + if (expression instanceof org.eclipse.jdt.internal.compiler.ast.QualifiedAllocationExpression) { + return convert((org.eclipse.jdt.internal.compiler.ast.QualifiedAllocationExpression) expression); + } + if (expression instanceof org.eclipse.jdt.internal.compiler.ast.AllocationExpression) { + return convert((org.eclipse.jdt.internal.compiler.ast.AllocationExpression) expression); + } + if (expression instanceof org.eclipse.jdt.internal.compiler.ast.ArrayInitializer) { + return convert((org.eclipse.jdt.internal.compiler.ast.ArrayInitializer) expression); + } + if (expression instanceof org.eclipse.jdt.internal.compiler.ast.PrefixExpression) { + return convert((org.eclipse.jdt.internal.compiler.ast.PrefixExpression) expression); + } + if (expression instanceof org.eclipse.jdt.internal.compiler.ast.PostfixExpression) { + return convert((org.eclipse.jdt.internal.compiler.ast.PostfixExpression) expression); + } + if (expression instanceof org.eclipse.jdt.internal.compiler.ast.CompoundAssignment) { + return convert((org.eclipse.jdt.internal.compiler.ast.CompoundAssignment) expression); + } + if (expression instanceof org.eclipse.jdt.internal.compiler.ast.Assignment) { + return convert((org.eclipse.jdt.internal.compiler.ast.Assignment) expression); + } + if (expression instanceof org.eclipse.jdt.internal.compiler.ast.ClassLiteralAccess) { + return convert((org.eclipse.jdt.internal.compiler.ast.ClassLiteralAccess) expression); + } + if (expression instanceof org.eclipse.jdt.internal.compiler.ast.FalseLiteral) { + return convert((org.eclipse.jdt.internal.compiler.ast.FalseLiteral) expression); + } + if (expression instanceof org.eclipse.jdt.internal.compiler.ast.TrueLiteral) { + return convert((org.eclipse.jdt.internal.compiler.ast.TrueLiteral) expression); + } + if (expression instanceof org.eclipse.jdt.internal.compiler.ast.NullLiteral) { + return convert((org.eclipse.jdt.internal.compiler.ast.NullLiteral) expression); + } + if (expression instanceof org.eclipse.jdt.internal.compiler.ast.CharLiteral) { + return convert((org.eclipse.jdt.internal.compiler.ast.CharLiteral) expression); + } + if (expression instanceof org.eclipse.jdt.internal.compiler.ast.DoubleLiteral) { + return convert((org.eclipse.jdt.internal.compiler.ast.DoubleLiteral) expression); + } + if (expression instanceof org.eclipse.jdt.internal.compiler.ast.FloatLiteral) { + return convert((org.eclipse.jdt.internal.compiler.ast.FloatLiteral) expression); + } + if (expression instanceof org.eclipse.jdt.internal.compiler.ast.IntLiteralMinValue) { + return convert((org.eclipse.jdt.internal.compiler.ast.IntLiteralMinValue) expression); + } + if (expression instanceof org.eclipse.jdt.internal.compiler.ast.IntLiteral) { + return convert((org.eclipse.jdt.internal.compiler.ast.IntLiteral) expression); + } + if (expression instanceof org.eclipse.jdt.internal.compiler.ast.LongLiteralMinValue) { + return convert((org.eclipse.jdt.internal.compiler.ast.LongLiteralMinValue) expression); + } + if (expression instanceof org.eclipse.jdt.internal.compiler.ast.LongLiteral) { + return convert((org.eclipse.jdt.internal.compiler.ast.LongLiteral) expression); + } + if (expression instanceof StringLiteralConcatenation) { + return convert((StringLiteralConcatenation) expression); + } + if (expression instanceof org.eclipse.jdt.internal.compiler.ast.ExtendedStringLiteral) { + return convert((org.eclipse.jdt.internal.compiler.ast.ExtendedStringLiteral) expression); + } + if (expression instanceof org.eclipse.jdt.internal.compiler.ast.StringLiteral) { + return convert((org.eclipse.jdt.internal.compiler.ast.StringLiteral) expression); + } + if (expression instanceof org.eclipse.jdt.internal.compiler.ast.AND_AND_Expression) { + return convert((org.eclipse.jdt.internal.compiler.ast.AND_AND_Expression) expression); + } + if (expression instanceof org.eclipse.jdt.internal.compiler.ast.OR_OR_Expression) { + return convert((org.eclipse.jdt.internal.compiler.ast.OR_OR_Expression) expression); + } + if (expression instanceof org.eclipse.jdt.internal.compiler.ast.EqualExpression) { + return convert((org.eclipse.jdt.internal.compiler.ast.EqualExpression) expression); + } + if (expression instanceof org.eclipse.jdt.internal.compiler.ast.BinaryExpression) { + return convert((org.eclipse.jdt.internal.compiler.ast.BinaryExpression) expression); + } + if (expression instanceof org.eclipse.jdt.internal.compiler.ast.InstanceOfExpression) { + return convert((org.eclipse.jdt.internal.compiler.ast.InstanceOfExpression) expression); + } + if (expression instanceof org.eclipse.jdt.internal.compiler.ast.UnaryExpression) { + return convert((org.eclipse.jdt.internal.compiler.ast.UnaryExpression) expression); + } + if (expression instanceof org.eclipse.jdt.internal.compiler.ast.ConditionalExpression) { + return convert((org.eclipse.jdt.internal.compiler.ast.ConditionalExpression) expression); + } + if (expression instanceof org.eclipse.jdt.internal.compiler.ast.MessageSend) { + return convert((org.eclipse.jdt.internal.compiler.ast.MessageSend) expression); + } + if (expression instanceof org.eclipse.jdt.internal.compiler.ast.Reference) { + return convert((org.eclipse.jdt.internal.compiler.ast.Reference) expression); + } + if (expression instanceof org.eclipse.jdt.internal.compiler.ast.TypeReference) { + return convert((org.eclipse.jdt.internal.compiler.ast.TypeReference) expression); + } + if (expression instanceof org.eclipse.objectteams.otdt.internal.core.compiler.ast.BaseCallMessageSend) + { + return convert(((org.eclipse.objectteams.otdt.internal.core.compiler.ast.BaseCallMessageSend) expression)); + } + if (expression instanceof org.eclipse.objectteams.otdt.internal.core.compiler.ast.ParameterMapping) + { + return convert((org.eclipse.objectteams.otdt.internal.core.compiler.ast.ParameterMapping) expression); + } + if (expression instanceof org.eclipse.objectteams.otdt.internal.core.compiler.ast.PotentialTranslationExpression) + { + // Note (SH): this includes Potential{Lifting,Lowering}Expresssion: + return convert(((org.eclipse.objectteams.otdt.internal.core.compiler.ast.PotentialTranslationExpression)expression).expression); + } + org.eclipse.jdt.internal.compiler.ast.Expression unwrapped = Lowering.unwrapExpression(expression); + if (unwrapped != null) + { + return convert(unwrapped); + } +//gbr} + return null; + } + + public StringLiteral convert(org.eclipse.jdt.internal.compiler.ast.ExtendedStringLiteral expression) { + expression.computeConstant(); + StringLiteral literal = new StringLiteral(this.ast); + if (this.resolveBindings) { + this.recordNodes(literal, expression); + } + literal.setLiteralValue(expression.constant.stringValue()); + literal.setSourceRange(expression.sourceStart, expression.sourceEnd - expression.sourceStart + 1); + return literal; + } + + public BooleanLiteral convert(org.eclipse.jdt.internal.compiler.ast.FalseLiteral expression) { + final BooleanLiteral literal = new BooleanLiteral(this.ast); + literal.setBooleanValue(false); + if (this.resolveBindings) { + this.recordNodes(literal, expression); + } + literal.setSourceRange(expression.sourceStart, expression.sourceEnd - expression.sourceStart + 1); + return literal; + } + + public Expression convert(org.eclipse.jdt.internal.compiler.ast.FieldReference reference) { + if (reference.receiver.isSuper()) { + final SuperFieldAccess superFieldAccess = new SuperFieldAccess(this.ast); + if (this.resolveBindings) { + recordNodes(superFieldAccess, reference); + } + if (reference.receiver instanceof org.eclipse.jdt.internal.compiler.ast.QualifiedSuperReference) { + Name qualifier = convert((org.eclipse.jdt.internal.compiler.ast.QualifiedSuperReference) reference.receiver); + superFieldAccess.setQualifier(qualifier); + if (this.resolveBindings) { + recordNodes(qualifier, reference.receiver); + } + } + final SimpleName simpleName = new SimpleName(this.ast); + simpleName.internalSetIdentifier(new String(reference.token)); + int sourceStart = (int)(reference.nameSourcePosition>>>32); + int length = (int)(reference.nameSourcePosition & 0xFFFFFFFF) - sourceStart + 1; + simpleName.setSourceRange(sourceStart, length); + superFieldAccess.setName(simpleName); + if (this.resolveBindings) { + recordNodes(simpleName, reference); + } + superFieldAccess.setSourceRange(reference.receiver.sourceStart, reference.sourceEnd - reference.receiver.sourceStart + 1); + return superFieldAccess; + } else { + final FieldAccess fieldAccess = new FieldAccess(this.ast); + if (this.resolveBindings) { + recordNodes(fieldAccess, reference); + } + Expression receiver = convert(reference.receiver); + fieldAccess.setExpression(receiver); + final SimpleName simpleName = new SimpleName(this.ast); + simpleName.internalSetIdentifier(new String(reference.token)); + int sourceStart = (int)(reference.nameSourcePosition>>>32); + int length = (int)(reference.nameSourcePosition & 0xFFFFFFFF) - sourceStart + 1; + simpleName.setSourceRange(sourceStart, length); + fieldAccess.setName(simpleName); + if (this.resolveBindings) { + recordNodes(simpleName, reference); + } + fieldAccess.setSourceRange(receiver.getStartPosition(), reference.sourceEnd - receiver.getStartPosition() + 1); + return fieldAccess; + } + } + + public NumberLiteral convert(org.eclipse.jdt.internal.compiler.ast.FloatLiteral expression) { + int length = expression.sourceEnd - expression.sourceStart + 1; + int sourceStart = expression.sourceStart; + NumberLiteral literal = new NumberLiteral(this.ast); + literal.internalSetToken(new String(this.compilationUnitSource, sourceStart, length)); + if (this.resolveBindings) { + this.recordNodes(literal, expression); + } + literal.setSourceRange(sourceStart, length); + removeLeadingAndTrailingCommentsFromLiteral(literal); + return literal; + } + + public Statement convert(ForeachStatement statement) { + switch(this.ast.apiLevel) { + case AST.JLS2_INTERNAL : + return createFakeEmptyStatement(statement); + case AST.JLS3 : + EnhancedForStatement enhancedForStatement = new EnhancedForStatement(this.ast); + enhancedForStatement.setParameter(convertToSingleVariableDeclaration(statement.elementVariable)); + org.eclipse.jdt.internal.compiler.ast.Expression collection = statement.collection; + if (collection == null) return null; + enhancedForStatement.setExpression(convert(collection)); + final Statement action = convert(statement.action); + if (action == null) return null; + enhancedForStatement.setBody(action); + int start = statement.sourceStart; + int end = statement.sourceEnd; + enhancedForStatement.setSourceRange(start, end - start + 1); + return enhancedForStatement; + default: + return createFakeEmptyStatement(statement); + } + } + + public ForStatement convert(org.eclipse.jdt.internal.compiler.ast.ForStatement statement) { + ForStatement forStatement = new ForStatement(this.ast); + forStatement.setSourceRange(statement.sourceStart, statement.sourceEnd - statement.sourceStart + 1); + org.eclipse.jdt.internal.compiler.ast.Statement[] initializations = statement.initializations; + if (initializations != null) { + // we know that we have at least one initialization + if (initializations[0] instanceof org.eclipse.jdt.internal.compiler.ast.LocalDeclaration) { + org.eclipse.jdt.internal.compiler.ast.LocalDeclaration initialization = (org.eclipse.jdt.internal.compiler.ast.LocalDeclaration) initializations[0]; + VariableDeclarationExpression variableDeclarationExpression = convertToVariableDeclarationExpression(initialization); + int initializationsLength = initializations.length; + for (int i = 1; i < initializationsLength; i++) { + initialization = (org.eclipse.jdt.internal.compiler.ast.LocalDeclaration)initializations[i]; + variableDeclarationExpression.fragments().add(convertToVariableDeclarationFragment(initialization)); + } + if (initializationsLength != 1) { + int start = variableDeclarationExpression.getStartPosition(); + int end = ((org.eclipse.jdt.internal.compiler.ast.LocalDeclaration) initializations[initializationsLength - 1]).declarationSourceEnd; + variableDeclarationExpression.setSourceRange(start, end - start + 1); + } + forStatement.initializers().add(variableDeclarationExpression); + } else { + int initializationsLength = initializations.length; + for (int i = 0; i < initializationsLength; i++) { + Expression initializer = convertToExpression(initializations[i]); + if (initializer != null) { + forStatement.initializers().add(initializer); + } else { + forStatement.setFlags(forStatement.getFlags() | ASTNode.MALFORMED); + } + } + } + } + if (statement.condition != null) { + forStatement.setExpression(convert(statement.condition)); + } + org.eclipse.jdt.internal.compiler.ast.Statement[] increments = statement.increments; + if (increments != null) { + int incrementsLength = increments.length; + for (int i = 0; i < incrementsLength; i++) { + forStatement.updaters().add(convertToExpression(increments[i])); + } + } + final Statement action = convert(statement.action); + if (action == null) return null; + forStatement.setBody(action); + return forStatement; + } + + public IfStatement convert(org.eclipse.jdt.internal.compiler.ast.IfStatement statement) { + IfStatement ifStatement = new IfStatement(this.ast); + ifStatement.setSourceRange(statement.sourceStart, statement.sourceEnd - statement.sourceStart + 1); + ifStatement.setExpression(convert(statement.condition)); + final Statement thenStatement = convert(statement.thenStatement); + if (thenStatement == null) return null; + ifStatement.setThenStatement(thenStatement); + org.eclipse.jdt.internal.compiler.ast.Statement statement2 = statement.elseStatement; + if (statement2 != null) { + final Statement elseStatement = convert(statement2); + if (elseStatement != null) { + ifStatement.setElseStatement(elseStatement); + } + } + return ifStatement; + } + + public InstanceofExpression convert(org.eclipse.jdt.internal.compiler.ast.InstanceOfExpression expression) { + InstanceofExpression instanceOfExpression = new InstanceofExpression(this.ast); + if (this.resolveBindings) { + recordNodes(instanceOfExpression, expression); + } + Expression leftExpression = convert(expression.expression); + instanceOfExpression.setLeftOperand(leftExpression); + final Type convertType = convertType(expression.type); + instanceOfExpression.setRightOperand(convertType); + int startPosition = leftExpression.getStartPosition(); + int sourceEnd = convertType.getStartPosition() + convertType.getLength() - 1; + instanceOfExpression.setSourceRange(startPosition, sourceEnd - startPosition + 1); + return instanceOfExpression; + } + + public NumberLiteral convert(org.eclipse.jdt.internal.compiler.ast.IntLiteral expression) { + int length = expression.sourceEnd - expression.sourceStart + 1; + int sourceStart = expression.sourceStart; + final NumberLiteral literal = new NumberLiteral(this.ast); + literal.internalSetToken(new String(this.compilationUnitSource, sourceStart, length)); + if (this.resolveBindings) { + this.recordNodes(literal, expression); + } + literal.setSourceRange(sourceStart, length); + removeLeadingAndTrailingCommentsFromLiteral(literal); + return literal; + } + + public NumberLiteral convert(org.eclipse.jdt.internal.compiler.ast.IntLiteralMinValue expression) { + int length = expression.sourceEnd - expression.sourceStart + 1; + int sourceStart = expression.sourceStart; + NumberLiteral literal = new NumberLiteral(this.ast); + literal.internalSetToken(new String(this.compilationUnitSource, sourceStart, length)); + if (this.resolveBindings) { + this.recordNodes(literal, expression); + } + literal.setSourceRange(sourceStart, length); + removeLeadingAndTrailingCommentsFromLiteral(literal); + return literal; + } + + public void convert(org.eclipse.jdt.internal.compiler.ast.Javadoc javadoc, BodyDeclaration bodyDeclaration) { + if (bodyDeclaration.getJavadoc() == null) { + if (javadoc != null) { + if (this.commentMapper == null || !this.commentMapper.hasSameTable(this.commentsTable)) { + this.commentMapper = new DefaultCommentMapper(this.commentsTable); + } + Comment comment = this.commentMapper.getComment(javadoc.sourceStart); + if (comment != null && comment.isDocComment() && comment.getParent() == null) { + Javadoc docComment = (Javadoc) comment; + if (this.resolveBindings) { + recordNodes(docComment, javadoc); + // resolve member and method references binding + Iterator tags = docComment.tags().listIterator(); + while (tags.hasNext()) { + recordNodes(javadoc, (TagElement) tags.next()); + } + } + bodyDeclaration.setJavadoc(docComment); + } + } + } + } + + public void convert(org.eclipse.jdt.internal.compiler.ast.Javadoc javadoc, PackageDeclaration packageDeclaration) { + if (this.ast.apiLevel == AST.JLS3 && packageDeclaration.getJavadoc() == null) { + if (javadoc != null) { + if (this.commentMapper == null || !this.commentMapper.hasSameTable(this.commentsTable)) { + this.commentMapper = new DefaultCommentMapper(this.commentsTable); + } + Comment comment = this.commentMapper.getComment(javadoc.sourceStart); + if (comment != null && comment.isDocComment() && comment.getParent() == null) { + Javadoc docComment = (Javadoc) comment; + if (this.resolveBindings) { + recordNodes(docComment, javadoc); + // resolve member and method references binding + Iterator tags = docComment.tags().listIterator(); + while (tags.hasNext()) { + recordNodes(javadoc, (TagElement) tags.next()); + } + } + packageDeclaration.setJavadoc(docComment); + } + } + } + } + + public LabeledStatement convert(org.eclipse.jdt.internal.compiler.ast.LabeledStatement statement) { + LabeledStatement labeledStatement = new LabeledStatement(this.ast); + final int sourceStart = statement.sourceStart; + labeledStatement.setSourceRange(sourceStart, statement.sourceEnd - sourceStart + 1); + Statement body = convert(statement.statement); + if (body == null) return null; + labeledStatement.setBody(body); + final SimpleName name = new SimpleName(this.ast); + name.internalSetIdentifier(new String(statement.label)); + name.setSourceRange(sourceStart, statement.labelEnd - sourceStart + 1); + labeledStatement.setLabel(name); + return labeledStatement; + } + + public NumberLiteral convert(org.eclipse.jdt.internal.compiler.ast.LongLiteral expression) { + int length = expression.sourceEnd - expression.sourceStart + 1; + int sourceStart = expression.sourceStart; + final NumberLiteral literal = new NumberLiteral(this.ast); + literal.internalSetToken(new String(this.compilationUnitSource, sourceStart, length)); + if (this.resolveBindings) { + this.recordNodes(literal, expression); + } + literal.setSourceRange(sourceStart, length); + removeLeadingAndTrailingCommentsFromLiteral(literal); + return literal; + } + + public NumberLiteral convert(org.eclipse.jdt.internal.compiler.ast.LongLiteralMinValue expression) { + int length = expression.sourceEnd - expression.sourceStart + 1; + int sourceStart = expression.sourceStart; + final NumberLiteral literal = new NumberLiteral(this.ast); + literal.internalSetToken(new String(this.compilationUnitSource, sourceStart, length)); + if (this.resolveBindings) { + this.recordNodes(literal, expression); + } + literal.setSourceRange(sourceStart, length); + removeLeadingAndTrailingCommentsFromLiteral(literal); + return literal; + } + + public Expression convert(MessageSend expression) { + // will return a MethodInvocation or a SuperMethodInvocation or + Expression expr; + int sourceStart = expression.sourceStart; + +//{ObjectTeams: convert tsuper.methodName() and return TSuperMessageSend + + // conversion of compiler ast nodes for tsuper method invocation. + // The compiler ast uses TSuperMessageSend instead of MessageSend. + if (expression instanceof org.eclipse.objectteams.otdt.internal.core.compiler.ast.TSuperMessageSend) + { + org.eclipse.jdt.core.dom.TSuperMessageSend result = this.ast.newTSuperMessageSend(); + result.setSourceRange(expression.sourceStart, expression.sourceEnd - expression.sourceStart + 1); + + org.eclipse.objectteams.otdt.internal.core.compiler.ast.TSuperMessageSend send = + (org.eclipse.objectteams.otdt.internal.core.compiler.ast.TSuperMessageSend)expression; + org.eclipse.objectteams.otdt.internal.core.compiler.ast.TsuperReference tsuperRef = send.tsuperReference; + TypeReference typeReference = tsuperRef.qualification; + if (typeReference != null) { + Name qualification = null; + if (typeReference instanceof QualifiedTypeReference) + { + long[] poss = ((QualifiedTypeReference)typeReference).sourcePositions; + qualification = setQualifiedNameNameAndSourceRanges(typeReference.getTypeName(), poss, tsuperRef); + } else { + qualification = this.ast.newSimpleName(new String(((SingleTypeReference)typeReference).token)); + qualification.setSourceRange(typeReference.sourceStart, typeReference.sourceEnd); + } + result.setQualification(qualification); + } + + + SimpleName name = this.ast.newSimpleName(new String(expression.selector)); + int start = (int)(expression.nameSourcePosition >>> 32); + int end = (int)(expression.nameSourcePosition & 0xFFFFFFFF); + name.setSourceRange(start, end-start+1); + + if (this.resolveBindings) { + recordNodes(name, expression); + recordNodes(result, expression); + } + result.setName(name); + + org.eclipse.jdt.internal.compiler.ast.Expression[] arguments = expression.arguments; + if (arguments != null) + { + int argumentsLength = arguments.length; + argumentsLength--; //without marker element + for (int idx = 0; idx < argumentsLength; idx++) + { + Expression argExpr = convert(arguments[idx]); + if (this.resolveBindings) + { + recordNodes(argExpr, arguments[idx]); + } + result.getArguments().add(argExpr); + } + } + return result; + } +//mkr} + if (expression.isSuperAccess()) { + // returns a SuperMethodInvocation + final SuperMethodInvocation superMethodInvocation = new SuperMethodInvocation(this.ast); + if (this.resolveBindings) { + recordNodes(superMethodInvocation, expression); + } + final SimpleName name = new SimpleName(this.ast); + name.internalSetIdentifier(new String(expression.selector)); + int nameSourceStart = (int) (expression.nameSourcePosition >>> 32); + int nameSourceLength = ((int) expression.nameSourcePosition) - nameSourceStart + 1; + name.setSourceRange(nameSourceStart, nameSourceLength); + if (this.resolveBindings) { + recordNodes(name, expression); + } + superMethodInvocation.setName(name); + // expression.receiver is either a QualifiedSuperReference or a SuperReference + // so the casting cannot fail + if (expression.receiver instanceof org.eclipse.jdt.internal.compiler.ast.QualifiedSuperReference) { + Name qualifier = convert((org.eclipse.jdt.internal.compiler.ast.QualifiedSuperReference) expression.receiver); + superMethodInvocation.setQualifier(qualifier); + if (this.resolveBindings) { + recordNodes(qualifier, expression.receiver); + } + if (qualifier != null) { + sourceStart = qualifier.getStartPosition(); + } + } + org.eclipse.jdt.internal.compiler.ast.Expression[] arguments = expression.arguments; + if (arguments != null) { + int argumentsLength = arguments.length; + for (int i = 0; i < argumentsLength; i++) { + Expression expri = convert(arguments[i]); + if (this.resolveBindings) { + recordNodes(expri, arguments[i]); + } + superMethodInvocation.arguments().add(expri); + } + } + final TypeReference[] typeArguments = expression.typeArguments; + if (typeArguments != null) { + switch(this.ast.apiLevel) { + case AST.JLS2_INTERNAL : + superMethodInvocation.setFlags(superMethodInvocation.getFlags() | ASTNode.MALFORMED); + break; + case AST.JLS3 : + for (int i = 0, max = typeArguments.length; i < max; i++) { + superMethodInvocation.typeArguments().add(convertType(typeArguments[i])); + } + break; + } + } + expr = superMethodInvocation; + } else { + // returns a MethodInvocation + final MethodInvocation methodInvocation = new MethodInvocation(this.ast); + if (this.resolveBindings) { + recordNodes(methodInvocation, expression); + } + final SimpleName name = new SimpleName(this.ast); + name.internalSetIdentifier(new String(expression.selector)); + int nameSourceStart = (int) (expression.nameSourcePosition >>> 32); + int nameSourceLength = ((int) expression.nameSourcePosition) - nameSourceStart + 1; + name.setSourceRange(nameSourceStart, nameSourceLength); + methodInvocation.setName(name); + if (this.resolveBindings) { + recordNodes(name, expression); + } + org.eclipse.jdt.internal.compiler.ast.Expression[] arguments = expression.arguments; + if (arguments != null) { + int argumentsLength = arguments.length; + for (int i = 0; i < argumentsLength; i++) { + Expression expri = convert(arguments[i]); + if (this.resolveBindings) { + recordNodes(expri, arguments[i]); + } + methodInvocation.arguments().add(expri); + } + } + Expression qualifier = null; + org.eclipse.jdt.internal.compiler.ast.Expression receiver = expression.receiver; + if (receiver instanceof MessageSend) { + if ((receiver.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.ParenthesizedMASK) != 0) { + qualifier = convertToParenthesizedExpression(receiver); + } else { + qualifier = convert((MessageSend) receiver); + } + } else { + qualifier = convert(receiver); + } + if (qualifier instanceof Name && this.resolveBindings) { + recordNodes(qualifier, receiver); + } + methodInvocation.setExpression(qualifier); + if (qualifier != null) { + sourceStart = qualifier.getStartPosition(); + } + final TypeReference[] typeArguments = expression.typeArguments; + if (typeArguments != null) { + switch(this.ast.apiLevel) { + case AST.JLS2_INTERNAL : + methodInvocation.setFlags(methodInvocation.getFlags() | ASTNode.MALFORMED); + break; + case AST.JLS3 : + for (int i = 0, max = typeArguments.length; i < max; i++) { + methodInvocation.typeArguments().add(convertType(typeArguments[i])); + } + break; + } + } + expr = methodInvocation; + } + expr.setSourceRange(sourceStart, expression.sourceEnd - sourceStart + 1); + removeTrailingCommentFromExpressionEndingWithAParen(expr); + return expr; + } + + public MarkerAnnotation convert(org.eclipse.jdt.internal.compiler.ast.MarkerAnnotation annotation) { + final MarkerAnnotation markerAnnotation = new MarkerAnnotation(this.ast); + setTypeNameForAnnotation(annotation, markerAnnotation); + int start = annotation.sourceStart; + int end = annotation.declarationSourceEnd; + markerAnnotation.setSourceRange(start, end - start + 1); + if (this.resolveBindings) { + recordNodes(markerAnnotation, annotation); + markerAnnotation.resolveAnnotationBinding(); + } + return markerAnnotation; + } + + public MemberValuePair convert(org.eclipse.jdt.internal.compiler.ast.MemberValuePair memberValuePair) { + final MemberValuePair pair = new MemberValuePair(this.ast); + final SimpleName simpleName = new SimpleName(this.ast); + simpleName.internalSetIdentifier(new String(memberValuePair.name)); + int start = memberValuePair.sourceStart; + int end = memberValuePair.sourceEnd; + simpleName.setSourceRange(start, end - start + 1); + pair.setName(simpleName); + final Expression value = convert(memberValuePair.value); + pair.setValue(value); + start = memberValuePair.sourceStart; + end = value.getStartPosition() + value.getLength() - 1; + pair.setSourceRange(start, end - start + 1); + + if (memberValuePair.value instanceof SingleNameReference && + ((SingleNameReference)memberValuePair.value).token == RecoveryScanner.FAKE_IDENTIFIER) { + pair.setFlags(pair.getFlags() | ASTNode.RECOVERED); + } + + if (this.resolveBindings) { + recordNodes(simpleName, memberValuePair); + recordNodes(pair, memberValuePair); + } + return pair; + } + + public Name convert(org.eclipse.jdt.internal.compiler.ast.NameReference reference) { + if (reference instanceof org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference) { + return convert((org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference) reference); + } else { + return convert((org.eclipse.jdt.internal.compiler.ast.SingleNameReference) reference); + } + } + + public InfixExpression convert(StringLiteralConcatenation expression) { + expression.computeConstant(); + final InfixExpression infixExpression = new InfixExpression(this.ast); + infixExpression.setOperator(InfixExpression.Operator.PLUS); + org.eclipse.jdt.internal.compiler.ast.Expression[] stringLiterals = expression.literals; + infixExpression.setLeftOperand(convert(stringLiterals[0])); + infixExpression.setRightOperand(convert(stringLiterals[1])); + for (int i = 2; i < expression.counter; i++) { + infixExpression.extendedOperands().add(convert(stringLiterals[i])); + } + if (this.resolveBindings) { + this.recordNodes(infixExpression, expression); + } + infixExpression.setSourceRange(expression.sourceStart, expression.sourceEnd - expression.sourceStart + 1); + return infixExpression; + } + + public NormalAnnotation convert(org.eclipse.jdt.internal.compiler.ast.NormalAnnotation annotation) { + final NormalAnnotation normalAnnotation = new NormalAnnotation(this.ast); + setTypeNameForAnnotation(annotation, normalAnnotation); + + int start = annotation.sourceStart; + int end = annotation.declarationSourceEnd; + + org.eclipse.jdt.internal.compiler.ast.MemberValuePair[] memberValuePairs = annotation.memberValuePairs; + if (memberValuePairs != null) { + for (int i = 0, max = memberValuePairs.length; i < max; i++) { + MemberValuePair memberValuePair = convert(memberValuePairs[i]); + int memberValuePairEnd = memberValuePair.getStartPosition() + memberValuePair.getLength() - 1; + if (end == memberValuePairEnd) { + normalAnnotation.setFlags(normalAnnotation.getFlags() | ASTNode.RECOVERED); + } + normalAnnotation.values().add(memberValuePair); + } + } + + normalAnnotation.setSourceRange(start, end - start + 1); + if (this.resolveBindings) { + recordNodes(normalAnnotation, annotation); + normalAnnotation.resolveAnnotationBinding(); + } + return normalAnnotation; + } + + public NullLiteral convert(org.eclipse.jdt.internal.compiler.ast.NullLiteral expression) { + final NullLiteral literal = new NullLiteral(this.ast); + if (this.resolveBindings) { + this.recordNodes(literal, expression); + } + literal.setSourceRange(expression.sourceStart, expression.sourceEnd - expression.sourceStart + 1); + return literal; + } + + public Expression convert(org.eclipse.jdt.internal.compiler.ast.OR_OR_Expression expression) { + InfixExpression infixExpression = new InfixExpression(this.ast); + infixExpression.setOperator(InfixExpression.Operator.CONDITIONAL_OR); + if (this.resolveBindings) { + this.recordNodes(infixExpression, expression); + } + final int expressionOperatorID = (expression.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.OperatorMASK) >> org.eclipse.jdt.internal.compiler.ast.ASTNode.OperatorSHIFT; + if (expression.left instanceof org.eclipse.jdt.internal.compiler.ast.BinaryExpression + && ((expression.left.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.ParenthesizedMASK) == 0)) { + // create an extended string literal equivalent => use the extended operands list + infixExpression.extendedOperands().add(convert(expression.right)); + org.eclipse.jdt.internal.compiler.ast.Expression leftOperand = expression.left; + org.eclipse.jdt.internal.compiler.ast.Expression rightOperand = null; + do { + rightOperand = ((org.eclipse.jdt.internal.compiler.ast.BinaryExpression) leftOperand).right; + if ((((leftOperand.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.OperatorMASK) >> org.eclipse.jdt.internal.compiler.ast.ASTNode.OperatorSHIFT) != expressionOperatorID + && ((leftOperand.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.ParenthesizedMASK) == 0)) + || ((rightOperand instanceof org.eclipse.jdt.internal.compiler.ast.BinaryExpression + && ((rightOperand.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.OperatorMASK) >> org.eclipse.jdt.internal.compiler.ast.ASTNode.OperatorSHIFT) != expressionOperatorID) + && ((rightOperand.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.ParenthesizedMASK) == 0))) { + List extendedOperands = infixExpression.extendedOperands(); + InfixExpression temp = new InfixExpression(this.ast); + if (this.resolveBindings) { + this.recordNodes(temp, expression); + } + temp.setOperator(getOperatorFor(expressionOperatorID)); + Expression leftSide = convert(leftOperand); + temp.setLeftOperand(leftSide); + temp.setSourceRange(leftSide.getStartPosition(), leftSide.getLength()); + int size = extendedOperands.size(); + for (int i = 0; i < size - 1; i++) { + Expression expr = temp; + temp = new InfixExpression(this.ast); + + if (this.resolveBindings) { + this.recordNodes(temp, expression); + } + temp.setLeftOperand(expr); + temp.setOperator(getOperatorFor(expressionOperatorID)); + temp.setSourceRange(expr.getStartPosition(), expr.getLength()); + } + infixExpression = temp; + for (int i = 0; i < size; i++) { + Expression extendedOperand = (Expression) extendedOperands.remove(size - 1 - i); + temp.setRightOperand(extendedOperand); + int startPosition = temp.getLeftOperand().getStartPosition(); + temp.setSourceRange(startPosition, extendedOperand.getStartPosition() + extendedOperand.getLength() - startPosition); + if (temp.getLeftOperand().getNodeType() == ASTNode.INFIX_EXPRESSION) { + temp = (InfixExpression) temp.getLeftOperand(); + } + } + int startPosition = infixExpression.getLeftOperand().getStartPosition(); + infixExpression.setSourceRange(startPosition, expression.sourceEnd - startPosition + 1); + if (this.resolveBindings) { + this.recordNodes(infixExpression, expression); + } + return infixExpression; + } + infixExpression.extendedOperands().add(0, convert(rightOperand)); + leftOperand = ((org.eclipse.jdt.internal.compiler.ast.BinaryExpression) leftOperand).left; + } while (leftOperand instanceof org.eclipse.jdt.internal.compiler.ast.BinaryExpression && ((leftOperand.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.ParenthesizedMASK) == 0)); + Expression leftExpression = convert(leftOperand); + infixExpression.setLeftOperand(leftExpression); + infixExpression.setRightOperand((Expression)infixExpression.extendedOperands().remove(0)); + int startPosition = leftExpression.getStartPosition(); + infixExpression.setSourceRange(startPosition, expression.sourceEnd - startPosition + 1); + return infixExpression; + } + Expression leftExpression = convert(expression.left); + infixExpression.setLeftOperand(leftExpression); + infixExpression.setRightOperand(convert(expression.right)); + infixExpression.setOperator(InfixExpression.Operator.CONDITIONAL_OR); + int startPosition = leftExpression.getStartPosition(); + infixExpression.setSourceRange(startPosition, expression.sourceEnd - startPosition + 1); + return infixExpression; + } + + public PostfixExpression convert(org.eclipse.jdt.internal.compiler.ast.PostfixExpression expression) { + final PostfixExpression postfixExpression = new PostfixExpression(this.ast); + if (this.resolveBindings) { + recordNodes(postfixExpression, expression); + } + postfixExpression.setSourceRange(expression.sourceStart, expression.sourceEnd - expression.sourceStart + 1); + postfixExpression.setOperand(convert(expression.lhs)); + switch (expression.operator) { + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.PLUS : + postfixExpression.setOperator(PostfixExpression.Operator.INCREMENT); + break; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.MINUS : + postfixExpression.setOperator(PostfixExpression.Operator.DECREMENT); + break; + } + return postfixExpression; + } + + public PrefixExpression convert(org.eclipse.jdt.internal.compiler.ast.PrefixExpression expression) { + final PrefixExpression prefixExpression = new PrefixExpression(this.ast); + if (this.resolveBindings) { + recordNodes(prefixExpression, expression); + } + prefixExpression.setSourceRange(expression.sourceStart, expression.sourceEnd - expression.sourceStart + 1); + prefixExpression.setOperand(convert(expression.lhs)); + switch (expression.operator) { + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.PLUS : + prefixExpression.setOperator(PrefixExpression.Operator.INCREMENT); + break; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.MINUS : + prefixExpression.setOperator(PrefixExpression.Operator.DECREMENT); + break; + } + return prefixExpression; + } + + public Expression convert(org.eclipse.jdt.internal.compiler.ast.QualifiedAllocationExpression allocation) { + final ClassInstanceCreation classInstanceCreation = new ClassInstanceCreation(this.ast); + if (allocation.enclosingInstance != null) { + classInstanceCreation.setExpression(convert(allocation.enclosingInstance)); + } + switch(this.ast.apiLevel) { + case AST.JLS2_INTERNAL : + classInstanceCreation.internalSetName(convert(allocation.type)); + break; + case AST.JLS3 : + classInstanceCreation.setType(convertType(allocation.type)); + } + org.eclipse.jdt.internal.compiler.ast.Expression[] arguments = allocation.arguments; + if (arguments != null) { + int length = arguments.length; + for (int i = 0; i < length; i++) { + Expression argument = convert(arguments[i]); + if (this.resolveBindings) { + recordNodes(argument, arguments[i]); + } + classInstanceCreation.arguments().add(argument); + } + } + if (allocation.typeArguments != null) { + switch(this.ast.apiLevel) { + case AST.JLS2_INTERNAL : + classInstanceCreation.setFlags(classInstanceCreation.getFlags() | ASTNode.MALFORMED); + break; + case AST.JLS3 : + for (int i = 0, max = allocation.typeArguments.length; i < max; i++) { + classInstanceCreation.typeArguments().add(convertType(allocation.typeArguments[i])); + } + } + } + if (allocation.anonymousType != null) { + int declarationSourceStart = allocation.sourceStart; + classInstanceCreation.setSourceRange(declarationSourceStart, allocation.anonymousType.bodyEnd - declarationSourceStart + 1); + final AnonymousClassDeclaration anonymousClassDeclaration = new AnonymousClassDeclaration(this.ast); + int start = retrieveStartBlockPosition(allocation.anonymousType.sourceEnd, allocation.anonymousType.bodyEnd); + anonymousClassDeclaration.setSourceRange(start, allocation.anonymousType.bodyEnd - start + 1); + classInstanceCreation.setAnonymousClassDeclaration(anonymousClassDeclaration); + buildBodyDeclarations(allocation.anonymousType, anonymousClassDeclaration); + if (this.resolveBindings) { + recordNodes(classInstanceCreation, allocation.anonymousType); + recordNodes(anonymousClassDeclaration, allocation.anonymousType); + anonymousClassDeclaration.resolveBinding(); + } + return classInstanceCreation; + } else { + final int start = allocation.sourceStart; + classInstanceCreation.setSourceRange(start, allocation.sourceEnd - start + 1); + if (this.resolveBindings) { + recordNodes(classInstanceCreation, allocation); + } + removeTrailingCommentFromExpressionEndingWithAParen(classInstanceCreation); + return classInstanceCreation; + } + } + + public Name convert(org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference nameReference) { + return setQualifiedNameNameAndSourceRanges(nameReference.tokens, nameReference.sourcePositions, nameReference); + } + + public Name convert(org.eclipse.jdt.internal.compiler.ast.QualifiedSuperReference reference) { + return convert(reference.qualification); + } + +//{ObjectTeams: convert methods for OT-specific internal types +// BaseAllocationExpression, BaseCallMessageSend, +// QualifiedFakedBaseReference + +public BaseConstructorInvocation convert( + org.eclipse.objectteams.otdt.internal.core.compiler.ast.BaseAllocationExpression expr) { + BaseConstructorInvocation result = this.ast + .newBaseConstructorInvocation(); + result.setSourceRange(expr.sourceStart, expr.sourceEnd + - expr.sourceStart + 1); + if (this.resolveBindings) { + recordNodes(result, expr); + } + + // [SH]: expression is set during TransformStatements, will be null if + // errors encountered + if (expr.expression != null) { + org.eclipse.jdt.internal.compiler.ast.Expression[] arguments; + org.eclipse.jdt.internal.compiler.ast.Expression call = expr.expression; + if (call instanceof org.eclipse.jdt.internal.compiler.ast.CastExpression) + call = ((org.eclipse.jdt.internal.compiler.ast.CastExpression)call).expression; + if (call instanceof AllocationExpression) + arguments = ((AllocationExpression) call).arguments; + else if (call instanceof MessageSend) + arguments = ((MessageSend) call).arguments; // creator call + else + throw new InternalCompilerError("Unexpected expression type in BaseAllocationExpression"); //$NON-NLS-1$ + if (arguments != null) { + int argumentsLength = arguments.length; + for (int idx = 0; idx < argumentsLength; idx++) { + Expression argExpr = convert(arguments[idx]); + if (this.resolveBindings) { + recordNodes(argExpr, arguments[idx]); + } + result.getArguments().add(argExpr); + } + } + } + + return result; + } + + public org.eclipse.jdt.core.dom.BaseCallMessageSend convert( + org.eclipse.objectteams.otdt.internal.core.compiler.ast.BaseCallMessageSend expression) { + org.eclipse.jdt.core.dom.BaseCallMessageSend result = this.ast + .newBaseCallMessageSend(); + result.setSourceRange(expression.sourceStart, expression.sourceEnd + - expression.sourceStart + 1); + + MessageSend msgSend = expression.getMessageSend(); + char[] srcSelector = expression.sourceSelector; + SimpleName name = this.ast.newSimpleName(new String(srcSelector)); + int start = (int) (msgSend.nameSourcePosition >>> 32); + int end = (int) (msgSend.nameSourcePosition & 0xFFFFFFFF); + name.setSourceRange(start, end - start + 1); + + if (this.resolveBindings) { + recordNodes(name, expression); + recordNodes(result, expression); + } + result.setName(name); + + org.eclipse.jdt.internal.compiler.ast.Expression[] arguments = msgSend.arguments; + if (arguments != null) { + int argumentsLength = arguments.length; + // FIXME(SH): static? + for (int idx = MethodSignatureEnhancer.ENHANCING_ARG_LEN+1; idx < argumentsLength; idx++) { // +1: skip 'isSuperAccess' + Expression argExpr = convert(arguments[idx]); + if (this.resolveBindings) { + recordNodes(argExpr, arguments[idx]); + } + result.getArguments().add(argExpr); + } + } + return result; + } +//gbr} + + public ThisExpression convert(org.eclipse.jdt.internal.compiler.ast.QualifiedThisReference reference) { + final ThisExpression thisExpression = new ThisExpression(this.ast); + thisExpression.setSourceRange(reference.sourceStart, reference.sourceEnd - reference.sourceStart + 1); + thisExpression.setQualifier(convert(reference.qualification)); + if (this.resolveBindings) { + recordNodes(thisExpression, reference); + recordPendingThisExpressionScopeResolution(thisExpression); + } + return thisExpression; + } + + public Expression convert(org.eclipse.jdt.internal.compiler.ast.Reference reference) { + if (reference instanceof org.eclipse.jdt.internal.compiler.ast.NameReference) { + return convert((org.eclipse.jdt.internal.compiler.ast.NameReference) reference); + } +//{ObjectTeams: cases added for converting OT-specific internal types TSuperReference +// and BaseReference + if (reference instanceof TsuperReference) + { + return convert((TsuperReference)reference); + } + if (reference instanceof BaseReference) + { + return convert((BaseReference)reference); + } +//gbr} + if (reference instanceof org.eclipse.jdt.internal.compiler.ast.ThisReference) { + return convert((org.eclipse.jdt.internal.compiler.ast.ThisReference) reference); + } + if (reference instanceof org.eclipse.jdt.internal.compiler.ast.ArrayReference) { + return convert((org.eclipse.jdt.internal.compiler.ast.ArrayReference) reference); + } + if (reference instanceof org.eclipse.jdt.internal.compiler.ast.FieldReference) { + return convert((org.eclipse.jdt.internal.compiler.ast.FieldReference) reference); + } + return null; // cannot be reached + } + + public ReturnStatement convert(org.eclipse.jdt.internal.compiler.ast.ReturnStatement statement) { + final ReturnStatement returnStatement = new ReturnStatement(this.ast); + returnStatement.setSourceRange(statement.sourceStart, statement.sourceEnd - statement.sourceStart + 1); + if (statement.expression != null) { + returnStatement.setExpression(convert(statement.expression)); + } + return returnStatement; + } + + public SingleMemberAnnotation convert(org.eclipse.jdt.internal.compiler.ast.SingleMemberAnnotation annotation) { + final SingleMemberAnnotation singleMemberAnnotation = new SingleMemberAnnotation(this.ast); + setTypeNameForAnnotation(annotation, singleMemberAnnotation); + singleMemberAnnotation.setValue(convert(annotation.memberValue)); + int start = annotation.sourceStart; + int end = annotation.declarationSourceEnd; + singleMemberAnnotation.setSourceRange(start, end - start + 1); + if (this.resolveBindings) { + recordNodes(singleMemberAnnotation, annotation); + singleMemberAnnotation.resolveAnnotationBinding(); + } + return singleMemberAnnotation; + } + + public SimpleName convert(org.eclipse.jdt.internal.compiler.ast.SingleNameReference nameReference) { + final SimpleName name = new SimpleName(this.ast); + name.internalSetIdentifier(new String(nameReference.token)); + if (this.resolveBindings) { + recordNodes(name, nameReference); + } + name.setSourceRange(nameReference.sourceStart, nameReference.sourceEnd - nameReference.sourceStart + 1); + return name; + } + + public Statement convert(org.eclipse.jdt.internal.compiler.ast.Statement statement) { +//{ObjectTeams: don't convert generated statements + if (statement != null && statement.isGenerated()) + return null; +// SH} + if (statement instanceof ForeachStatement) { + return convert((ForeachStatement) statement); + } + if (statement instanceof org.eclipse.jdt.internal.compiler.ast.LocalDeclaration) { + org.eclipse.jdt.internal.compiler.ast.LocalDeclaration localDeclaration = (org.eclipse.jdt.internal.compiler.ast.LocalDeclaration)statement; + return convertToVariableDeclarationStatement(localDeclaration); + } + if (statement instanceof org.eclipse.jdt.internal.compiler.ast.AssertStatement) { + return convert((org.eclipse.jdt.internal.compiler.ast.AssertStatement) statement); + } +//{ObjectTeams: case added for converting OT-specific node WithinStatement + if (statement instanceof org.eclipse.objectteams.otdt.internal.core.compiler.ast.WithinStatement) + { + return convert((org.eclipse.objectteams.otdt.internal.core.compiler.ast.WithinStatement)statement); + } +//gbr} +//{ObjectTeams: handle BaseConstructorMessageSend. Note: might be unresolvable, i.e. incomplete rhs! + if (statement instanceof org.eclipse.objectteams.otdt.internal.core.compiler.ast.BaseAllocationExpression) { + return convert((org.eclipse.objectteams.otdt.internal.core.compiler.ast.BaseAllocationExpression) statement); + } +//carp} + if (statement instanceof org.eclipse.jdt.internal.compiler.ast.Block) { + return convert((org.eclipse.jdt.internal.compiler.ast.Block) statement); + } + if (statement instanceof org.eclipse.jdt.internal.compiler.ast.BreakStatement) { + return convert((org.eclipse.jdt.internal.compiler.ast.BreakStatement) statement); + } + if (statement instanceof org.eclipse.jdt.internal.compiler.ast.ContinueStatement) { + return convert((org.eclipse.jdt.internal.compiler.ast.ContinueStatement) statement); + } + if (statement instanceof org.eclipse.jdt.internal.compiler.ast.CaseStatement) { + return convert((org.eclipse.jdt.internal.compiler.ast.CaseStatement) statement); + } + if (statement instanceof org.eclipse.jdt.internal.compiler.ast.DoStatement) { + return convert((org.eclipse.jdt.internal.compiler.ast.DoStatement) statement); + } + if (statement instanceof org.eclipse.jdt.internal.compiler.ast.EmptyStatement) { + return convert((org.eclipse.jdt.internal.compiler.ast.EmptyStatement) statement); + } + if (statement instanceof org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall) { + return convert((org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall) statement); + } + if (statement instanceof org.eclipse.jdt.internal.compiler.ast.ForStatement) { + return convert((org.eclipse.jdt.internal.compiler.ast.ForStatement) statement); + } + if (statement instanceof org.eclipse.jdt.internal.compiler.ast.IfStatement) { + return convert((org.eclipse.jdt.internal.compiler.ast.IfStatement) statement); + } + if (statement instanceof org.eclipse.jdt.internal.compiler.ast.LabeledStatement) { + return convert((org.eclipse.jdt.internal.compiler.ast.LabeledStatement) statement); + } + if (statement instanceof org.eclipse.jdt.internal.compiler.ast.ReturnStatement) { + return convert((org.eclipse.jdt.internal.compiler.ast.ReturnStatement) statement); + } + if (statement instanceof org.eclipse.jdt.internal.compiler.ast.SwitchStatement) { + return convert((org.eclipse.jdt.internal.compiler.ast.SwitchStatement) statement); + } + if (statement instanceof org.eclipse.jdt.internal.compiler.ast.SynchronizedStatement) { + return convert((org.eclipse.jdt.internal.compiler.ast.SynchronizedStatement) statement); + } + if (statement instanceof org.eclipse.jdt.internal.compiler.ast.ThrowStatement) { + return convert((org.eclipse.jdt.internal.compiler.ast.ThrowStatement) statement); + } + if (statement instanceof org.eclipse.jdt.internal.compiler.ast.TryStatement) { + return convert((org.eclipse.jdt.internal.compiler.ast.TryStatement) statement); + } + if (statement instanceof org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) { + ASTNode result = convert((org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) statement); + if (result == null) { + return createFakeEmptyStatement(statement); + } + switch(result.getNodeType()) { + case ASTNode.ENUM_DECLARATION: + switch(this.ast.apiLevel) { + case AST.JLS2_INTERNAL : + return createFakeEmptyStatement(statement); + case AST.JLS3 : + final TypeDeclarationStatement typeDeclarationStatement = new TypeDeclarationStatement(this.ast); + typeDeclarationStatement.setDeclaration((EnumDeclaration) result); + AbstractTypeDeclaration typeDecl = typeDeclarationStatement.getDeclaration(); + typeDeclarationStatement.setSourceRange(typeDecl.getStartPosition(), typeDecl.getLength()); + return typeDeclarationStatement; + } + break; + case ASTNode.ANNOTATION_TYPE_DECLARATION : + switch(this.ast.apiLevel) { + case AST.JLS2_INTERNAL : + return createFakeEmptyStatement(statement); + case AST.JLS3 : + TypeDeclarationStatement typeDeclarationStatement = new TypeDeclarationStatement(this.ast); + typeDeclarationStatement.setDeclaration((AnnotationTypeDeclaration) result); + AbstractTypeDeclaration typeDecl = typeDeclarationStatement.getDeclaration(); + typeDeclarationStatement.setSourceRange(typeDecl.getStartPosition(), typeDecl.getLength()); + return typeDeclarationStatement; + } + break; + default: + TypeDeclaration typeDeclaration = (TypeDeclaration) result; + TypeDeclarationStatement typeDeclarationStatement = new TypeDeclarationStatement(this.ast); + typeDeclarationStatement.setDeclaration(typeDeclaration); + switch(this.ast.apiLevel) { + case AST.JLS2_INTERNAL : + TypeDeclaration typeDecl = typeDeclarationStatement.internalGetTypeDeclaration(); + typeDeclarationStatement.setSourceRange(typeDecl.getStartPosition(), typeDecl.getLength()); + break; + case AST.JLS3 : + AbstractTypeDeclaration typeDeclAST3 = typeDeclarationStatement.getDeclaration(); + typeDeclarationStatement.setSourceRange(typeDeclAST3.getStartPosition(), typeDeclAST3.getLength()); + break; + } + return typeDeclarationStatement; + } + } + if (statement instanceof org.eclipse.jdt.internal.compiler.ast.WhileStatement) { + return convert((org.eclipse.jdt.internal.compiler.ast.WhileStatement) statement); + } + if (statement instanceof org.eclipse.jdt.internal.compiler.ast.Expression) { + org.eclipse.jdt.internal.compiler.ast.Expression statement2 = (org.eclipse.jdt.internal.compiler.ast.Expression) statement; + final Expression expr = convert(statement2); + final ExpressionStatement stmt = new ExpressionStatement(this.ast); + stmt.setExpression(expr); + int sourceStart = expr.getStartPosition(); + int sourceEnd = statement2.statementEnd; + stmt.setSourceRange(sourceStart, sourceEnd - sourceStart + 1); + return stmt; + } + return createFakeEmptyStatement(statement); + } + + public Expression convert(org.eclipse.jdt.internal.compiler.ast.StringLiteral expression) { + if (expression instanceof StringLiteralConcatenation) { + return convert((StringLiteralConcatenation) expression); + } + int length = expression.sourceEnd - expression.sourceStart + 1; + int sourceStart = expression.sourceStart; + StringLiteral literal = new StringLiteral(this.ast); + if (this.resolveBindings) { + this.recordNodes(literal, expression); + } + literal.internalSetEscapedValue(new String(this.compilationUnitSource, sourceStart, length)); + literal.setSourceRange(expression.sourceStart, expression.sourceEnd - expression.sourceStart + 1); + return literal; + } + + public SwitchStatement convert(org.eclipse.jdt.internal.compiler.ast.SwitchStatement statement) { + SwitchStatement switchStatement = new SwitchStatement(this.ast); + switchStatement.setSourceRange(statement.sourceStart, statement.sourceEnd - statement.sourceStart + 1); + switchStatement.setExpression(convert(statement.expression)); + org.eclipse.jdt.internal.compiler.ast.Statement[] statements = statement.statements; + if (statements != null) { + int statementsLength = statements.length; + for (int i = 0; i < statementsLength; i++) { + if (statements[i] instanceof org.eclipse.jdt.internal.compiler.ast.LocalDeclaration) { + checkAndAddMultipleLocalDeclaration(statements, i, switchStatement.statements()); + } else { + final Statement currentStatement = convert(statements[i]); + if (currentStatement != null) { + switchStatement.statements().add(currentStatement); + } + } + } + } + return switchStatement; + } + + public SynchronizedStatement convert(org.eclipse.jdt.internal.compiler.ast.SynchronizedStatement statement) { + SynchronizedStatement synchronizedStatement = new SynchronizedStatement(this.ast); + synchronizedStatement.setSourceRange(statement.sourceStart, statement.sourceEnd - statement.sourceStart + 1); + synchronizedStatement.setBody(convert(statement.block)); + synchronizedStatement.setExpression(convert(statement.expression)); + return synchronizedStatement; + } + + public Expression convert(org.eclipse.jdt.internal.compiler.ast.ThisReference reference) { + if (reference.isImplicitThis()) { + // There is no source associated with an implicit this + return null; + } else if (reference instanceof org.eclipse.jdt.internal.compiler.ast.QualifiedSuperReference) { + return convert((org.eclipse.jdt.internal.compiler.ast.QualifiedSuperReference) reference); + } else if (reference instanceof org.eclipse.jdt.internal.compiler.ast.QualifiedThisReference) { + return convert((org.eclipse.jdt.internal.compiler.ast.QualifiedThisReference) reference); + } else { + ThisExpression thisExpression = new ThisExpression(this.ast); + thisExpression.setSourceRange(reference.sourceStart, reference.sourceEnd - reference.sourceStart + 1); + if (this.resolveBindings) { + recordNodes(thisExpression, reference); + recordPendingThisExpressionScopeResolution(thisExpression); + } + return thisExpression; + } + } + + public ThrowStatement convert(org.eclipse.jdt.internal.compiler.ast.ThrowStatement statement) { + final ThrowStatement throwStatement = new ThrowStatement(this.ast); + throwStatement.setSourceRange(statement.sourceStart, statement.sourceEnd - statement.sourceStart + 1); + throwStatement.setExpression(convert(statement.exception)); + return throwStatement; + } + + public BooleanLiteral convert(org.eclipse.jdt.internal.compiler.ast.TrueLiteral expression) { + final BooleanLiteral literal = new BooleanLiteral(this.ast); + literal.setBooleanValue(true); + if (this.resolveBindings) { + this.recordNodes(literal, expression); + } + literal.setSourceRange(expression.sourceStart, expression.sourceEnd - expression.sourceStart + 1); + return literal; + } + + public TryStatement convert(org.eclipse.jdt.internal.compiler.ast.TryStatement statement) { + final TryStatement tryStatement = new TryStatement(this.ast); + tryStatement.setSourceRange(statement.sourceStart, statement.sourceEnd - statement.sourceStart + 1); + + tryStatement.setBody(convert(statement.tryBlock)); + org.eclipse.jdt.internal.compiler.ast.Argument[] catchArguments = statement.catchArguments; + if (catchArguments != null) { + int catchArgumentsLength = catchArguments.length; + org.eclipse.jdt.internal.compiler.ast.Block[] catchBlocks = statement.catchBlocks; + int start = statement.tryBlock.sourceEnd; + for (int i = 0; i < catchArgumentsLength; i++) { + CatchClause catchClause = new CatchClause(this.ast); + int catchClauseSourceStart = retrieveStartingCatchPosition(start, catchArguments[i].sourceStart); + catchClause.setSourceRange(catchClauseSourceStart, catchBlocks[i].sourceEnd - catchClauseSourceStart + 1); + catchClause.setBody(convert(catchBlocks[i])); + catchClause.setException(convert(catchArguments[i])); + tryStatement.catchClauses().add(catchClause); + start = catchBlocks[i].sourceEnd; + } + } + if (statement.finallyBlock != null) { + tryStatement.setFinally(convert(statement.finallyBlock)); + } + return tryStatement; + } + + public ASTNode convert(org.eclipse.jdt.internal.compiler.ast.TypeDeclaration typeDeclaration) { + int kind = org.eclipse.jdt.internal.compiler.ast.TypeDeclaration.kind(typeDeclaration.modifiers); + switch (kind) { + case org.eclipse.jdt.internal.compiler.ast.TypeDeclaration.ENUM_DECL : + if (this.ast.apiLevel == AST.JLS2_INTERNAL) { + return null; + } else { + return convertToEnumDeclaration(typeDeclaration); + } + case org.eclipse.jdt.internal.compiler.ast.TypeDeclaration.ANNOTATION_TYPE_DECL : + if (this.ast.apiLevel == AST.JLS2_INTERNAL) { + return null; + } else { + return convertToAnnotationDeclaration(typeDeclaration); + } + } + + checkCanceled(); +//{ObjectTeams: if TypeDeclaration is a role, it is a RoleTypeDeclaration, otherwise it is just a + //TypeDeclaration + TypeDeclaration typeDecl; + if (!typeDeclaration.isRole()) + { +//ike} + typeDecl = new TypeDeclaration(this.ast); + if (typeDeclaration.modifiersSourceStart != -1) { + setModifiers(typeDecl, typeDeclaration); + } + typeDecl.setInterface(kind == org.eclipse.jdt.internal.compiler.ast.TypeDeclaration.INTERFACE_DECL); +//{ObjectTeams: type declaration can be a team class or a role class, too + typeDecl.setTeam(typeDeclaration.isTeam()); + typeDecl.setRole(typeDeclaration.isSourceRole()); +//gbr} + final SimpleName typeName = new SimpleName(this.ast); + typeName.internalSetIdentifier(new String(typeDeclaration.name)); + typeName.setSourceRange(typeDeclaration.sourceStart, typeDeclaration.sourceEnd - typeDeclaration.sourceStart + 1); + typeDecl.setName(typeName); + typeDecl.setSourceRange(typeDeclaration.declarationSourceStart, typeDeclaration.bodyEnd - typeDeclaration.declarationSourceStart + 1); + + // need to set the superclass and super interfaces here since we cannot distinguish them at + // the type references level. + if (typeDeclaration.superclass != null) { + switch(this.ast.apiLevel) { + case AST.JLS2_INTERNAL : + typeDecl.internalSetSuperclass(convert(typeDeclaration.superclass)); + break; + case AST.JLS3 : + typeDecl.setSuperclassType(convertType(typeDeclaration.superclass)); + break; + } + } + + org.eclipse.jdt.internal.compiler.ast.TypeReference[] superInterfaces = typeDeclaration.superInterfaces; + if (superInterfaces != null) { + switch(this.ast.apiLevel) { + case AST.JLS2_INTERNAL : + for (int index = 0, length = superInterfaces.length; index < length; index++) { + typeDecl.internalSuperInterfaces().add(convert(superInterfaces[index])); + } + break; + case AST.JLS3 : + for (int index = 0, length = superInterfaces.length; index < length; index++) { + typeDecl.superInterfaceTypes().add(convertType(superInterfaces[index])); + } + } + } + org.eclipse.jdt.internal.compiler.ast.TypeParameter[] typeParameters = typeDeclaration.typeParameters; + if (typeParameters != null) { + switch(this.ast.apiLevel) { + case AST.JLS2_INTERNAL : + typeDecl.setFlags(typeDecl.getFlags() | ASTNode.MALFORMED); + break; + case AST.JLS3 : + for (int index = 0, length = typeParameters.length; index < length; index++) { + typeDecl.typeParameters().add(convert(typeParameters[index])); + } + } + } + buildBodyDeclarations(typeDeclaration, typeDecl); + if (this.resolveBindings) { + recordNodes(typeDecl, typeDeclaration); + recordNodes(typeName, typeDeclaration); + typeDecl.resolveBinding(); + } +//{ObjectTeams: do OT-specific stuff + } + else + { + typeDecl = buildRoleTypeDeclaration(typeDeclaration); + } + org.eclipse.objectteams.otdt.internal.core.compiler.ast.GuardPredicateDeclaration guard = typeDeclaration.predicate; + if (guard != null) + typeDecl.setGuardPredicate(convertGuardPredicate(guard)); + if (typeDeclaration.precedences != null) + for (org.eclipse.objectteams.otdt.internal.core.compiler.ast.PrecedenceDeclaration aPrecedence : typeDeclaration.precedences) + typeDecl.precedences().add(convertPrecedence(aPrecedence)); +//ike} + return typeDecl; + } + +//{ObjectTeams: build RoleTypeDeclaration with inforamtions from Compiler.TypeDeclaration + private RoleTypeDeclaration buildRoleTypeDeclaration(org.eclipse.jdt.internal.compiler.ast.TypeDeclaration typeDeclaration) + { + RoleTypeDeclaration roleTypeDecl = this.ast.newRoleTypeDeclaration(); + char[] oldSource = null; + try { + if (typeDeclaration.isRoleFile()) { + if (typeDeclaration.isConverted) + return null; // don't convert role files which may not have enough source information + if (typeDeclaration.compilationResult.compilationUnit != null) + { + oldSource = this.scanner.source; // try again (see revert in 3857 but also change in 5472..) + this.scanner.setSource(typeDeclaration.compilationResult); + this.compilationUnitSource = this.scanner.source; + this.compilationUnitSourceLength = this.scanner.source.length; + } + roleTypeDecl.setRoleFile(true); + } + + //km: modifers are handled differently in JLS3 + switch(this.ast.apiLevel) { + case AST.JLS2_INTERNAL: { + int modifiers = typeDeclaration.modifiers; + modifiers &= ~ClassFileConstants.AccInterface; // remove AccInterface flags + // also allow additional flag to be passed: (how about deprecated?) + modifiers &= ExtraCompilerModifiers.AccOTTypeJustFlag; + roleTypeDecl.setModifiers(modifiers); + + if (typeDeclaration.baseclass != null) + roleTypeDecl.setBaseClass(convert(typeDeclaration.baseclass)); + + // need to set the superclass and super interfaces here since we cannot distinguish them at + // the type references level. + if (typeDeclaration.superclass != null) + roleTypeDecl.setSuperclass(convert(typeDeclaration.superclass)); + + } + break; + case AST.JLS3: + this.setModifiers(roleTypeDecl, typeDeclaration); + + if ( typeDeclaration.baseclass != null + && !typeDeclaration.baseclass.isGenerated()) + roleTypeDecl.setBaseClassType(convertType(typeDeclaration.baseclass)); + + // need to set the superclass and super interfaces here since we cannot distinguish them at + // the type references level. + if ( typeDeclaration.superclass != null + && !typeDeclaration.superclass.isGenerated()) + roleTypeDecl.setSuperclassType(convertType(typeDeclaration.superclass)); + + break; + } + + roleTypeDecl.setInterface(typeDeclaration.isInterface()); + roleTypeDecl.setTeam(typeDeclaration.isTeam()); + roleTypeDecl.setRole(typeDeclaration.isSourceRole()); + + SimpleName typeName = this.ast.newSimpleName( + getRealName(typeDeclaration.name) + ); + + typeName.setSourceRange(typeDeclaration.sourceStart, typeDeclaration.sourceEnd - typeDeclaration.sourceStart + 1); + roleTypeDecl.setName(typeName); + roleTypeDecl.setSourceRange(typeDeclaration.declarationSourceStart, typeDeclaration.bodyEnd - typeDeclaration.declarationSourceStart + 1); + + // fetch superInterfaces from the interface part of the role: + org.eclipse.jdt.internal.compiler.ast.TypeReference[] superInterfaces = null; + RoleModel roleModel = typeDeclaration.getRoleModel(); + if ( !typeDeclaration.isInterface() // class? + && roleModel != null && roleModel.hasState(ITranslationStates.STATE_ROLES_SPLIT)) // has been split? + { + org.eclipse.jdt.internal.compiler.ast.TypeDeclaration ifcDecl = roleModel.getInterfaceAst(); + if (ifcDecl != null) + superInterfaces = ifcDecl.superInterfaces; + } else { + superInterfaces = typeDeclaration.superInterfaces; + } + if (superInterfaces != null) + for (int index = 0, length = superInterfaces.length; index < length; index++) + if (!superInterfaces[index].isGenerated()) + roleTypeDecl.superInterfaceTypes().add(convertType(superInterfaces[index])); + + org.eclipse.objectteams.otdt.internal.core.compiler.ast.GuardPredicateDeclaration guard = typeDeclaration.predicate; + if (guard != null) + roleTypeDecl.setGuardPredicate(convertGuardPredicate(guard)); + + buildBodyDeclarations(typeDeclaration, roleTypeDecl); + + SimpleName teamClassName = null; + if (typeDeclaration.enclosingType!=null) + { + org.eclipse.jdt.internal.compiler.ast.TypeDeclaration teamDecl + = typeDeclaration.enclosingType; + teamClassName = this.ast.newSimpleName(new String(teamDecl.name)); + teamClassName.setSourceRange(teamDecl.sourceStart, teamDecl.sourceEnd - teamDecl.sourceStart + 1); + if(this.ast.apiLevel == AST.JLS3){ + SimpleType teamType = this.ast.newSimpleType(teamClassName); + teamType.setSourceRange(teamClassName.getStartPosition(), teamClassName.getLength()); + roleTypeDecl.setTeamClassType(teamType); + } + else + roleTypeDecl.setTeamClass(teamClassName); + } + + if (this.resolveBindings) + { + recordNodes(roleTypeDecl, typeDeclaration); + recordNodes(typeName, typeDeclaration); + recordNodes(teamClassName, typeDeclaration.enclosingType); + roleTypeDecl.resolveBinding(); + } + return roleTypeDecl; + } finally { + if (oldSource != null) { + this.scanner.setSource(oldSource); + this.compilationUnitSource = oldSource; + this.compilationUnitSourceLength = oldSource.length; + } + } + } + + /** Retrieve the sibling type declaration corresponding to superIfcBinding. */ + private TypeReference[] getInterfacePartInterfaces( + org.eclipse.jdt.internal.compiler.ast.TypeDeclaration typeDeclaration, + TypeBinding superIfcBinding) + { + org.eclipse.jdt.internal.compiler.ast.TypeDeclaration enclosing = typeDeclaration.enclosingType; + if (enclosing == null) + return null; + if (enclosing.memberTypes == null) + return null; + for (org.eclipse.jdt.internal.compiler.ast.TypeDeclaration memberType : enclosing.memberTypes) + if (memberType.binding == superIfcBinding) + return memberType.superInterfaces; + + return null; + } + + private String getRealName(char[] name) + { + if (name == null || name.length == 0) + { + return ""; // //$NON-NLS-1$ + } + String realName; + String[] nameTokens = new String (name).split(IOTConstants.OT_DELIM); + realName = nameTokens[nameTokens.length-1]; + return realName; + } + + private PrecedenceDeclaration convertPrecedence(org.eclipse.objectteams.otdt.internal.core.compiler.ast.PrecedenceDeclaration aPrecedence) + { + PrecedenceDeclaration newPrecedence = this.ast.newPrecedenceDeclaration(); + newPrecedence.setSourceRange(aPrecedence.declarationSourceStart, aPrecedence.sourceEnd - aPrecedence.declarationSourceStart + 1); + for (org.eclipse.jdt.internal.compiler.ast.NameReference nameRef: aPrecedence.bindingNames) { + newPrecedence.elements().add(convert(nameRef)); + } + return newPrecedence; + } + + private GuardPredicateDeclaration convertGuardPredicate(org.eclipse.objectteams.otdt.internal.core.compiler.ast.GuardPredicateDeclaration guard) { + GuardPredicateDeclaration newGuard = this.ast.newGuardPredicateDeclaration(); + newGuard.setSourceRange(guard.declarationSourceStart, guard.declarationSourceEnd - guard.declarationSourceStart + 1); + if (guard.hasParsedStatements) { + org.eclipse.jdt.internal.compiler.ast.ReturnStatement returnStat = guard.returnStatement; + newGuard.setExpression(convert(returnStat.expression)); + } + newGuard.setBase(guard.isBasePredicate); + return newGuard; + } + +//ike+SH} + + + public TypeParameter convert(org.eclipse.jdt.internal.compiler.ast.TypeParameter typeParameter) { + final TypeParameter typeParameter2 = new TypeParameter(this.ast); +//{ObjectTeams: distinguish TypeValueParameter: + if (typeParameter.getKind() == org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration.TYPE_VALUE_PARAMETER) + typeParameter2.setIsValueParameter(true); +// SH} + final SimpleName simpleName = new SimpleName(this.ast); + simpleName.internalSetIdentifier(new String(typeParameter.name)); + int start = typeParameter.sourceStart; + int end = typeParameter.sourceEnd; + simpleName.setSourceRange(start, end - start + 1); + typeParameter2.setName(simpleName); + final TypeReference superType = typeParameter.type; + end = typeParameter.declarationSourceEnd; + if (superType != null) { + Type type = convertType(superType); + typeParameter2.typeBounds().add(type); + end = type.getStartPosition() + type.getLength() - 1; + } + TypeReference[] bounds = typeParameter.bounds; + if (bounds != null) { + Type type = null; + for (int index = 0, length = bounds.length; index < length; index++) { + type = convertType(bounds[index]); + typeParameter2.typeBounds().add(type); + end = type.getStartPosition() + type.getLength() - 1; + } +//{ObjectTeams: mark <B base R>: + if (typeParameter.hasBaseBound()) + typeParameter2.setHasBaseBound(true); +// SH} + } + start = typeParameter.declarationSourceStart; + end = retrieveClosingAngleBracketPosition(end); + typeParameter2.setSourceRange(start, end - start + 1); + if (this.resolveBindings) { + recordName(simpleName, typeParameter); + recordNodes(typeParameter2, typeParameter); + typeParameter2.resolveBinding(); + } + return typeParameter2; + } + + public Name convert(org.eclipse.jdt.internal.compiler.ast.TypeReference typeReference) { + char[][] typeName = typeReference.getTypeName(); + int length = typeName.length; + if (length > 1) { +//{ObjectTeams: catch qualified lifting types + // TODO (SH): we probably need information about both names in a lifting type?? + if (typeReference instanceof LiftingTypeReference) + typeReference = ((LiftingTypeReference)typeReference).baseReference; +// SH} + // QualifiedName + org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference qualifiedTypeReference = (org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference) typeReference; + final long[] positions = qualifiedTypeReference.sourcePositions; + return setQualifiedNameNameAndSourceRanges(typeName, positions, typeReference); + } else { + final SimpleName name = new SimpleName(this.ast); + name.internalSetIdentifier(new String(typeName[0])); + name.setSourceRange(typeReference.sourceStart, typeReference.sourceEnd - typeReference.sourceStart + 1); + name.index = 1; + if (this.resolveBindings) { + recordNodes(name, typeReference); + } + return name; + } + } + + public PrefixExpression convert(org.eclipse.jdt.internal.compiler.ast.UnaryExpression expression) { + final PrefixExpression prefixExpression = new PrefixExpression(this.ast); + if (this.resolveBindings) { + this.recordNodes(prefixExpression, expression); + } + prefixExpression.setSourceRange(expression.sourceStart, expression.sourceEnd - expression.sourceStart + 1); + prefixExpression.setOperand(convert(expression.expression)); + switch ((expression.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.OperatorMASK) >> org.eclipse.jdt.internal.compiler.ast.ASTNode.OperatorSHIFT) { + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.PLUS : + prefixExpression.setOperator(PrefixExpression.Operator.PLUS); + break; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.MINUS : + prefixExpression.setOperator(PrefixExpression.Operator.MINUS); + break; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.NOT : + prefixExpression.setOperator(PrefixExpression.Operator.NOT); + break; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.TWIDDLE : + prefixExpression.setOperator(PrefixExpression.Operator.COMPLEMENT); + } + return prefixExpression; + } + + public WhileStatement convert(org.eclipse.jdt.internal.compiler.ast.WhileStatement statement) { + final WhileStatement whileStatement = new WhileStatement(this.ast); + whileStatement.setSourceRange(statement.sourceStart, statement.sourceEnd - statement.sourceStart + 1); + whileStatement.setExpression(convert(statement.condition)); + final Statement action = convert(statement.action); + if (action == null) return null; + whileStatement.setBody(action); + return whileStatement; + } + + public ImportDeclaration convertImport(org.eclipse.jdt.internal.compiler.ast.ImportReference importReference) { + final ImportDeclaration importDeclaration = new ImportDeclaration(this.ast); + final boolean onDemand = (importReference.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.OnDemand) != 0; + final char[][] tokens = importReference.tokens; + int length = importReference.tokens.length; + final long[] positions = importReference.sourcePositions; + if (length > 1) { + importDeclaration.setName(setQualifiedNameNameAndSourceRanges(tokens, positions, importReference)); + } else { + final SimpleName name = new SimpleName(this.ast); + name.internalSetIdentifier(new String(tokens[0])); + final int start = (int)(positions[0]>>>32); + final int end = (int)(positions[0] & 0xFFFFFFFF); + name.setSourceRange(start, end - start + 1); + name.index = 1; + importDeclaration.setName(name); + if (this.resolveBindings) { + recordNodes(name, importReference); + } + } + importDeclaration.setSourceRange(importReference.declarationSourceStart, importReference.declarationEnd - importReference.declarationSourceStart + 1); + importDeclaration.setOnDemand(onDemand); + int modifiers = importReference.modifiers; + if (modifiers != ClassFileConstants.AccDefault) { + switch(this.ast.apiLevel) { + case AST.JLS2_INTERNAL : + importDeclaration.setFlags(importDeclaration.getFlags() | ASTNode.MALFORMED); + break; + case AST.JLS3 : + if (modifiers == ClassFileConstants.AccStatic) { + importDeclaration.setStatic(true); + } else { + importDeclaration.setFlags(importDeclaration.getFlags() | ASTNode.MALFORMED); + } +//{ObjectTeams: base imports: + if (modifiers == ExtraCompilerModifiers.AccBase) { + importDeclaration.setBase(true); + } else { + importDeclaration.setFlags(importDeclaration.getFlags() | ASTNode.MALFORMED); + } +// SH} + } + } + if (this.resolveBindings) { + recordNodes(importDeclaration, importReference); + } + return importDeclaration; + } + + public PackageDeclaration convertPackage(org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration compilationUnitDeclaration) { + org.eclipse.jdt.internal.compiler.ast.ImportReference importReference = compilationUnitDeclaration.currentPackage; + final PackageDeclaration packageDeclaration = new PackageDeclaration(this.ast); + final char[][] tokens = importReference.tokens; + final int length = importReference.tokens.length; + long[] positions = importReference.sourcePositions; + if (length > 1) { + packageDeclaration.setName(setQualifiedNameNameAndSourceRanges(tokens, positions, importReference)); + } else { + final SimpleName name = new SimpleName(this.ast); + name.internalSetIdentifier(new String(tokens[0])); + int start = (int)(positions[0]>>>32); + int end = (int)(positions[length - 1] & 0xFFFFFFFF); + name.setSourceRange(start, end - start + 1); + name.index = 1; + packageDeclaration.setName(name); + if (this.resolveBindings) { + recordNodes(name, compilationUnitDeclaration); + } + } + packageDeclaration.setSourceRange(importReference.declarationSourceStart, importReference.declarationEnd - importReference.declarationSourceStart + 1); + org.eclipse.jdt.internal.compiler.ast.Annotation[] annotations = importReference.annotations; + if (annotations != null) { + switch(this.ast.apiLevel) { + case AST.JLS2_INTERNAL : + packageDeclaration.setFlags(packageDeclaration.getFlags() & ASTNode.MALFORMED); + break; + case AST.JLS3 : + for (int i = 0, max = annotations.length; i < max; i++) { + packageDeclaration.annotations().add(convert(annotations[i])); + } + } + } + if (this.resolveBindings) { + recordNodes(packageDeclaration, importReference); + } + // Set javadoc + convert(compilationUnitDeclaration.javadoc, packageDeclaration); + return packageDeclaration; + } + + private EnumDeclaration convertToEnumDeclaration(org.eclipse.jdt.internal.compiler.ast.TypeDeclaration typeDeclaration) { + checkCanceled(); + // enum declaration cannot be built if the source is not >= 1.5, since enum is then seen as an identifier + final EnumDeclaration enumDeclaration2 = new EnumDeclaration(this.ast); + setModifiers(enumDeclaration2, typeDeclaration); + final SimpleName typeName = new SimpleName(this.ast); + typeName.internalSetIdentifier(new String(typeDeclaration.name)); + typeName.setSourceRange(typeDeclaration.sourceStart, typeDeclaration.sourceEnd - typeDeclaration.sourceStart + 1); + enumDeclaration2.setName(typeName); + enumDeclaration2.setSourceRange(typeDeclaration.declarationSourceStart, typeDeclaration.bodyEnd - typeDeclaration.declarationSourceStart + 1); + + org.eclipse.jdt.internal.compiler.ast.TypeReference[] superInterfaces = typeDeclaration.superInterfaces; + if (superInterfaces != null) { + for (int index = 0, length = superInterfaces.length; index < length; index++) { + enumDeclaration2.superInterfaceTypes().add(convertType(superInterfaces[index])); + } + } + buildBodyDeclarations(typeDeclaration, enumDeclaration2); + if (this.resolveBindings) { + recordNodes(enumDeclaration2, typeDeclaration); + recordNodes(typeName, typeDeclaration); + enumDeclaration2.resolveBinding(); + } + return enumDeclaration2; + } + public Expression convertToExpression(org.eclipse.jdt.internal.compiler.ast.Statement statement) { + if (statement instanceof org.eclipse.jdt.internal.compiler.ast.Expression) { + return convert((org.eclipse.jdt.internal.compiler.ast.Expression) statement); + } else { + return null; + } + } + + protected FieldDeclaration convertToFieldDeclaration(org.eclipse.jdt.internal.compiler.ast.FieldDeclaration fieldDecl) { + VariableDeclarationFragment variableDeclarationFragment = convertToVariableDeclarationFragment(fieldDecl); + final FieldDeclaration fieldDeclaration = new FieldDeclaration(this.ast); + fieldDeclaration.fragments().add(variableDeclarationFragment); + if (this.resolveBindings) { + recordNodes(variableDeclarationFragment, fieldDecl); + variableDeclarationFragment.resolveBinding(); + } + fieldDeclaration.setSourceRange(fieldDecl.declarationSourceStart, fieldDecl.declarationEnd - fieldDecl.declarationSourceStart + 1); + Type type = convertType(fieldDecl.type); + setTypeForField(fieldDeclaration, type, variableDeclarationFragment.getExtraDimensions()); + setModifiers(fieldDeclaration, fieldDecl); + convert(fieldDecl.javadoc, fieldDeclaration); + return fieldDeclaration; + } + + public ParenthesizedExpression convertToParenthesizedExpression(org.eclipse.jdt.internal.compiler.ast.Expression expression) { + final ParenthesizedExpression parenthesizedExpression = new ParenthesizedExpression(this.ast); + if (this.resolveBindings) { + recordNodes(parenthesizedExpression, expression); + } + parenthesizedExpression.setSourceRange(expression.sourceStart, expression.sourceEnd - expression.sourceStart + 1); + adjustSourcePositionsForParent(expression); + trimWhiteSpacesAndComments(expression); + // decrement the number of parenthesis + int numberOfParenthesis = (expression.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.ParenthesizedMASK) >> org.eclipse.jdt.internal.compiler.ast.ASTNode.ParenthesizedSHIFT; + expression.bits &= ~org.eclipse.jdt.internal.compiler.ast.ASTNode.ParenthesizedMASK; + expression.bits |= (numberOfParenthesis - 1) << org.eclipse.jdt.internal.compiler.ast.ASTNode.ParenthesizedSHIFT; + parenthesizedExpression.setExpression(convert(expression)); + return parenthesizedExpression; + } + + public Type convertToType(org.eclipse.jdt.internal.compiler.ast.NameReference reference) { + Name name = convert(reference); + final SimpleType type = new SimpleType(this.ast); + type.setName(name); + type.setSourceRange(name.getStartPosition(), name.getLength()); + if (this.resolveBindings) { + this.recordNodes(type, reference); + } + return type; + } + + protected VariableDeclarationExpression convertToVariableDeclarationExpression(org.eclipse.jdt.internal.compiler.ast.LocalDeclaration localDeclaration) { + final VariableDeclarationFragment variableDeclarationFragment = convertToVariableDeclarationFragment(localDeclaration); + final VariableDeclarationExpression variableDeclarationExpression = new VariableDeclarationExpression(this.ast); + variableDeclarationExpression.fragments().add(variableDeclarationFragment); + if (this.resolveBindings) { + recordNodes(variableDeclarationFragment, localDeclaration); + } + variableDeclarationExpression.setSourceRange(localDeclaration.declarationSourceStart, localDeclaration.declarationSourceEnd - localDeclaration.declarationSourceStart + 1); + Type type = convertType(localDeclaration.type); + setTypeForVariableDeclarationExpression(variableDeclarationExpression, type, variableDeclarationFragment.getExtraDimensions()); + if (localDeclaration.modifiersSourceStart != -1) { + setModifiers(variableDeclarationExpression, localDeclaration); + } + return variableDeclarationExpression; + } + + protected SingleVariableDeclaration convertToSingleVariableDeclaration(LocalDeclaration localDeclaration) { + final SingleVariableDeclaration variableDecl = new SingleVariableDeclaration(this.ast); + setModifiers(variableDecl, localDeclaration); + final SimpleName name = new SimpleName(this.ast); + name.internalSetIdentifier(new String(localDeclaration.name)); + int start = localDeclaration.sourceStart; + int nameEnd = localDeclaration.sourceEnd; + name.setSourceRange(start, nameEnd - start + 1); + variableDecl.setName(name); + final int extraDimensions = retrieveExtraDimension(nameEnd + 1, localDeclaration.type.sourceEnd); + variableDecl.setExtraDimensions(extraDimensions); + Type type = convertType(localDeclaration.type); + int typeEnd = type.getStartPosition() + type.getLength() - 1; + int rightEnd = Math.max(typeEnd, localDeclaration.declarationSourceEnd); + /* + * There is extra work to do to set the proper type positions + * See PR http://bugs.eclipse.org/bugs/show_bug.cgi?id=23284 + */ + setTypeForSingleVariableDeclaration(variableDecl, type, extraDimensions); + variableDecl.setSourceRange(localDeclaration.declarationSourceStart, rightEnd - localDeclaration.declarationSourceStart + 1); + if (this.resolveBindings) { + recordNodes(name, localDeclaration); + recordNodes(variableDecl, localDeclaration); + variableDecl.resolveBinding(); + } + return variableDecl; + } + + protected VariableDeclarationFragment convertToVariableDeclarationFragment(org.eclipse.jdt.internal.compiler.ast.FieldDeclaration fieldDeclaration) { + final VariableDeclarationFragment variableDeclarationFragment = new VariableDeclarationFragment(this.ast); + final SimpleName name = new SimpleName(this.ast); + name.internalSetIdentifier(new String(fieldDeclaration.name)); + name.setSourceRange(fieldDeclaration.sourceStart, fieldDeclaration.sourceEnd - fieldDeclaration.sourceStart + 1); + variableDeclarationFragment.setName(name); + int start = fieldDeclaration.sourceEnd; + int end = start; + int extraDimensions = retrieveExtraDimension(fieldDeclaration.sourceEnd + 1, fieldDeclaration.declarationSourceEnd ); + variableDeclarationFragment.setExtraDimensions(extraDimensions); + if (fieldDeclaration.initialization != null) { + final Expression expression = convert(fieldDeclaration.initialization); + variableDeclarationFragment.setInitializer(expression); + start = expression.getStartPosition() + expression.getLength(); + end = start - 1; + } else { + // we need to do it even if extendedDimension is null in case of syntax error in an array initializer + // need the exclusive range for retrieveEndOfPotentialExtendedDimensions + int possibleEnd = retrieveEndOfPotentialExtendedDimensions(start + 1, fieldDeclaration.sourceEnd, fieldDeclaration.declarationSourceEnd); + if (possibleEnd == Integer.MIN_VALUE) { + end = fieldDeclaration.declarationSourceEnd; + variableDeclarationFragment.setFlags(variableDeclarationFragment.getFlags() | ASTNode.MALFORMED); + } if (possibleEnd < 0) { + end = -possibleEnd; + variableDeclarationFragment.setFlags(variableDeclarationFragment.getFlags() | ASTNode.MALFORMED); + } else { + end = possibleEnd; + } + } + variableDeclarationFragment.setSourceRange(fieldDeclaration.sourceStart, end - fieldDeclaration.sourceStart + 1); + if (this.resolveBindings) { + recordNodes(name, fieldDeclaration); + recordNodes(variableDeclarationFragment, fieldDeclaration); + variableDeclarationFragment.resolveBinding(); + } + return variableDeclarationFragment; + } + + protected VariableDeclarationFragment convertToVariableDeclarationFragment(org.eclipse.jdt.internal.compiler.ast.LocalDeclaration localDeclaration) { + final VariableDeclarationFragment variableDeclarationFragment = new VariableDeclarationFragment(this.ast); + final SimpleName name = new SimpleName(this.ast); + name.internalSetIdentifier(new String(localDeclaration.name)); + name.setSourceRange(localDeclaration.sourceStart, localDeclaration.sourceEnd - localDeclaration.sourceStart + 1); + variableDeclarationFragment.setName(name); + int start = localDeclaration.sourceEnd; + org.eclipse.jdt.internal.compiler.ast.Expression initialization = localDeclaration.initialization; + int extraDimension = retrieveExtraDimension(localDeclaration.sourceEnd + 1, this.compilationUnitSourceLength); + variableDeclarationFragment.setExtraDimensions(extraDimension); + boolean hasInitialization = initialization != null; + int end; + if (hasInitialization) { + final Expression expression = convert(initialization); + variableDeclarationFragment.setInitializer(expression); + start = expression.getStartPosition() + expression.getLength(); + end = start - 1; + } else { + // we need to do it even if extendedDimension is null in case of syntax error in an array initializer + // start + 1 because we need the exclusive range for retrieveEndOfPotentialExtendedDimensions + int possibleEnd = retrieveEndOfPotentialExtendedDimensions(start + 1, localDeclaration.sourceEnd, localDeclaration.declarationSourceEnd); + if (possibleEnd == Integer.MIN_VALUE) { + end = start; + variableDeclarationFragment.setFlags(variableDeclarationFragment.getFlags() | ASTNode.MALFORMED); + } else if (possibleEnd < 0) { + end = -possibleEnd; + variableDeclarationFragment.setFlags(variableDeclarationFragment.getFlags() | ASTNode.MALFORMED); + } else { + end = possibleEnd; + } + } + variableDeclarationFragment.setSourceRange(localDeclaration.sourceStart, end - localDeclaration.sourceStart + 1); + if (this.resolveBindings) { + recordNodes(variableDeclarationFragment, localDeclaration); + recordNodes(name, localDeclaration); + variableDeclarationFragment.resolveBinding(); + } + return variableDeclarationFragment; + } + + protected VariableDeclarationStatement convertToVariableDeclarationStatement(org.eclipse.jdt.internal.compiler.ast.LocalDeclaration localDeclaration) { + final VariableDeclarationFragment variableDeclarationFragment = convertToVariableDeclarationFragment(localDeclaration); + final VariableDeclarationStatement variableDeclarationStatement = new VariableDeclarationStatement(this.ast); + variableDeclarationStatement.fragments().add(variableDeclarationFragment); + if (this.resolveBindings) { + recordNodes(variableDeclarationFragment, localDeclaration); + } + variableDeclarationStatement.setSourceRange(localDeclaration.declarationSourceStart, localDeclaration.declarationSourceEnd - localDeclaration.declarationSourceStart + 1); + Type type = convertType(localDeclaration.type); + setTypeForVariableDeclarationStatement(variableDeclarationStatement, type, variableDeclarationFragment.getExtraDimensions()); + if (localDeclaration.modifiersSourceStart != -1) { + setModifiers(variableDeclarationStatement, localDeclaration); + } + return variableDeclarationStatement; + } + + public Type convertType(TypeReference typeReference) { + if (typeReference instanceof Wildcard) { + final Wildcard wildcard = (Wildcard) typeReference; + final WildcardType wildcardType = new WildcardType(this.ast); + if (wildcard.bound != null) { + final Type bound = convertType(wildcard.bound); + wildcardType.setBound(bound, wildcard.kind == Wildcard.EXTENDS); + int start = wildcard.sourceStart; + wildcardType.setSourceRange(start, bound.getStartPosition() + bound.getLength() - start); + } else { + final int start = wildcard.sourceStart; + final int end = wildcard.sourceEnd; + wildcardType.setSourceRange(start, end - start + 1); + } + if (this.resolveBindings) { + recordNodes(wildcardType, typeReference); + } + return wildcardType; + } + Type type = null; + int sourceStart = -1; + int length = 0; + int dimensions = typeReference.dimensions(); +//{ObjectTeams: check for lifting type reference + if (typeReference instanceof LiftingTypeReference) + { + return convertType((LiftingTypeReference)typeReference); + } + if (typeReference instanceof TypeAnchorReference) + { + return convertType((TypeAnchorReference)typeReference); + } +//gbr+SH} + if (typeReference instanceof org.eclipse.jdt.internal.compiler.ast.SingleTypeReference) { + // this is either an ArrayTypeReference or a SingleTypeReference + char[] name = ((org.eclipse.jdt.internal.compiler.ast.SingleTypeReference) typeReference).getTypeName()[0]; + sourceStart = typeReference.sourceStart; + length = typeReference.sourceEnd - typeReference.sourceStart + 1; + // need to find out if this is an array type of primitive types or not + if (isPrimitiveType(name)) { + int end = retrieveEndOfElementTypeNamePosition(sourceStart, sourceStart + length); + if (end == -1) { + end = sourceStart + length - 1; + } + final PrimitiveType primitiveType = new PrimitiveType(this.ast); + primitiveType.setPrimitiveTypeCode(getPrimitiveTypeCode(name)); + primitiveType.setSourceRange(sourceStart, end - sourceStart + 1); + type = primitiveType; + } else if (typeReference instanceof ParameterizedSingleTypeReference) { + ParameterizedSingleTypeReference parameterizedSingleTypeReference = (ParameterizedSingleTypeReference) typeReference; + final SimpleName simpleName = new SimpleName(this.ast); + simpleName.internalSetIdentifier(new String(name)); + int end = retrieveEndOfElementTypeNamePosition(sourceStart, sourceStart + length); + if (end == -1) { + end = sourceStart + length - 1; + } + simpleName.setSourceRange(sourceStart, end - sourceStart + 1); + switch(this.ast.apiLevel) { + case AST.JLS2_INTERNAL : + SimpleType simpleType = new SimpleType(this.ast); + simpleType.setName(simpleName); + simpleType.setFlags(simpleType.getFlags() | ASTNode.MALFORMED); + simpleType.setSourceRange(sourceStart, end - sourceStart + 1); + type = simpleType; + if (this.resolveBindings) { + this.recordNodes(simpleName, typeReference); + } + break; + case AST.JLS3 : + simpleType = new SimpleType(this.ast); + simpleType.setName(simpleName); + simpleType.setSourceRange(simpleName.getStartPosition(), simpleName.getLength()); + final ParameterizedType parameterizedType = new ParameterizedType(this.ast); + parameterizedType.setType(simpleType); + type = parameterizedType; +//{ObjectTeams:??type anchors: + TypeAnchorReference[] typeAnchors = parameterizedSingleTypeReference.typeAnchors; + if (typeAnchors != null){ + for (TypeAnchorReference typeAnchor: typeAnchors) { + TypeAnchor anchorRef = convertType(typeAnchor); + parameterizedType.typeArguments().add(anchorRef); + end = anchorRef.getStartPosition() + anchorRef.getLength() - 1; + } + } +// SH} + TypeReference[] typeArguments = parameterizedSingleTypeReference.typeArguments; + if (typeArguments != null) { + Type type2 = null; + for (int i = 0, max = typeArguments.length; i < max; i++) { + type2 = convertType(typeArguments[i]); + ((ParameterizedType) type).typeArguments().add(type2); + end = type2.getStartPosition() + type2.getLength() - 1; + } + end = retrieveClosingAngleBracketPosition(end + 1); + type.setSourceRange(sourceStart, end - sourceStart + 1); + } else { + type.setSourceRange(sourceStart, end - sourceStart + 1); + } + if (this.resolveBindings) { + this.recordNodes(simpleName, typeReference); + this.recordNodes(simpleType, typeReference); + } + } + } else { + final SimpleName simpleName = new SimpleName(this.ast); + simpleName.internalSetIdentifier(new String(name)); + // we need to search for the starting position of the first brace in order to set the proper length + // PR http://dev.eclipse.org/bugs/show_bug.cgi?id=10759 + int end = retrieveEndOfElementTypeNamePosition(sourceStart, sourceStart + length); + if (end == -1) { + end = sourceStart + length - 1; + } + simpleName.setSourceRange(sourceStart, end - sourceStart + 1); + final SimpleType simpleType = new SimpleType(this.ast); + simpleType.setName(simpleName); + type = simpleType; + type.setSourceRange(sourceStart, end - sourceStart + 1); + type = simpleType; + if (this.resolveBindings) { + this.recordNodes(simpleName, typeReference); + } + } + if (dimensions != 0) { + type = this.ast.newArrayType(type, dimensions); + type.setSourceRange(sourceStart, length); + ArrayType subarrayType = (ArrayType) type; + int index = dimensions - 1; + while (index > 0) { + subarrayType = (ArrayType) subarrayType.getComponentType(); + int end = retrieveProperRightBracketPosition(index, sourceStart); + subarrayType.setSourceRange(sourceStart, end - sourceStart + 1); + index--; + } + if (this.resolveBindings) { + // store keys for inner types + completeRecord((ArrayType) type, typeReference); + } + } + } else { + if (typeReference instanceof ParameterizedQualifiedTypeReference) { + ParameterizedQualifiedTypeReference parameterizedQualifiedTypeReference = (ParameterizedQualifiedTypeReference) typeReference; + char[][] tokens = parameterizedQualifiedTypeReference.tokens; + TypeReference[][] typeArguments = parameterizedQualifiedTypeReference.typeArguments; + long[] positions = parameterizedQualifiedTypeReference.sourcePositions; + sourceStart = (int)(positions[0]>>>32); + switch(this.ast.apiLevel) { + case AST.JLS2_INTERNAL : { + char[][] name = ((org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference) typeReference).getTypeName(); + int nameLength = name.length; + sourceStart = (int)(positions[0]>>>32); + length = (int)(positions[nameLength - 1] & 0xFFFFFFFF) - sourceStart + 1; + Name qualifiedName = this.setQualifiedNameNameAndSourceRanges(name, positions, typeReference); + final SimpleType simpleType = new SimpleType(this.ast); + simpleType.setName(qualifiedName); + simpleType.setSourceRange(sourceStart, length); + type = simpleType; + } + break; + case AST.JLS3 : + if (typeArguments != null) { + int numberOfEnclosingType = 0; + int startingIndex = 0; + int endingIndex = 0; + for (int i = 0, max = typeArguments.length; i < max; i++) { + if (typeArguments[i] != null) { + numberOfEnclosingType++; + } else if (numberOfEnclosingType == 0) { + endingIndex++; + } + } + Name name = null; + if (endingIndex - startingIndex == 0) { + final SimpleName simpleName = new SimpleName(this.ast); + simpleName.internalSetIdentifier(new String(tokens[startingIndex])); + recordPendingNameScopeResolution(simpleName); + int start = (int)(positions[startingIndex]>>>32); + int end = (int) positions[startingIndex]; + simpleName.setSourceRange(start, end - start + 1); + simpleName.index = 1; + name = simpleName; + if (this.resolveBindings) { + recordNodes(simpleName, typeReference); + } + } else { + name = this.setQualifiedNameNameAndSourceRanges(tokens, positions, endingIndex, typeReference); + } + SimpleType simpleType = new SimpleType(this.ast); + simpleType.setName(name); + int start = (int)(positions[startingIndex]>>>32); + int end = (int) positions[endingIndex]; + simpleType.setSourceRange(start, end - start + 1); + ParameterizedType parameterizedType = new ParameterizedType(this.ast); + parameterizedType.setType(simpleType); + if (this.resolveBindings) { + recordNodes(simpleType, typeReference); + recordNodes(parameterizedType, typeReference); + } + start = simpleType.getStartPosition(); + end = start + simpleType.getLength() - 1; + for (int i = 0, max = typeArguments[endingIndex].length; i < max; i++) { + final Type type2 = convertType(typeArguments[endingIndex][i]); + parameterizedType.typeArguments().add(type2); + end = type2.getStartPosition() + type2.getLength() - 1; + } + int indexOfEnclosingType = 1; + parameterizedType.index = indexOfEnclosingType; + end = retrieveClosingAngleBracketPosition(end + 1); + length = end + 1; + parameterizedType.setSourceRange(start, end - start + 1); + startingIndex = endingIndex + 1; + Type currentType = parameterizedType; + while(startingIndex < typeArguments.length) { + SimpleName simpleName = new SimpleName(this.ast); + simpleName.internalSetIdentifier(new String(tokens[startingIndex])); + simpleName.index = startingIndex + 1; + start = (int)(positions[startingIndex]>>>32); + end = (int) positions[startingIndex]; + simpleName.setSourceRange(start, end - start + 1); + recordPendingNameScopeResolution(simpleName); + QualifiedType qualifiedType = new QualifiedType(this.ast); + qualifiedType.setQualifier(currentType); + qualifiedType.setName(simpleName); + if (this.resolveBindings) { + recordNodes(simpleName, typeReference); + recordNodes(qualifiedType, typeReference); + } + start = currentType.getStartPosition(); + end = simpleName.getStartPosition() + simpleName.getLength() - 1; + qualifiedType.setSourceRange(start, end - start + 1); + indexOfEnclosingType++; + if (typeArguments[startingIndex] != null) { + qualifiedType.index = indexOfEnclosingType; + ParameterizedType parameterizedType2 = new ParameterizedType(this.ast); + parameterizedType2.setType(qualifiedType); + parameterizedType2.index = indexOfEnclosingType; + if (this.resolveBindings) { + recordNodes(parameterizedType2, typeReference); + } + for (int i = 0, max = typeArguments[startingIndex].length; i < max; i++) { + final Type type2 = convertType(typeArguments[startingIndex][i]); + parameterizedType2.typeArguments().add(type2); + end = type2.getStartPosition() + type2.getLength() - 1; + } + end = retrieveClosingAngleBracketPosition(end + 1); + length = end + 1; + parameterizedType2.setSourceRange(start, end - start + 1); + currentType = parameterizedType2; + } else { + currentType = qualifiedType; + qualifiedType.index = indexOfEnclosingType; + } + startingIndex++; + } + if (this.resolveBindings) { + this.recordNodes(currentType, typeReference); + } + type = currentType; + length -= sourceStart; + } + } + } else { + char[][] name = ((org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference) typeReference).getTypeName(); +//{ObjectTeams: revert anchored types like in MyTeam.this._OT$base.R => base.R + org.eclipse.jdt.internal.compiler.lookup.TypeBinding typeBinding = + ((org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference) typeReference).resolvedType; + if (typeBinding != null) { + typeBinding = typeBinding.leafComponentType(); + if (typeBinding instanceof RoleTypeBinding) { + RoleTypeBinding rtb = (RoleTypeBinding)typeBinding; + if (rtb.hasExplicitAnchor()) { + char[][] newName = CharOperation.splitOn('.', rtb.optimalName()); + // refuse to use best name which is longer than source name. + if (name.length >= newName.length) + name = newName; + } + } + } +// SH} + int nameLength = name.length; + long[] positions = ((org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference) typeReference).sourcePositions; + sourceStart = (int)(positions[0]>>>32); + length = (int)(positions[nameLength - 1] & 0xFFFFFFFF) - sourceStart + 1; + final Name qualifiedName = this.setQualifiedNameNameAndSourceRanges(name, positions, typeReference); + final SimpleType simpleType = new SimpleType(this.ast); + simpleType.setName(qualifiedName); + type = simpleType; + type.setSourceRange(sourceStart, length); + } + + length = typeReference.sourceEnd - sourceStart + 1; + if (dimensions != 0) { + type = this.ast.newArrayType(type, dimensions); + if (this.resolveBindings) { + completeRecord((ArrayType) type, typeReference); + } + int end = retrieveEndOfDimensionsPosition(sourceStart+length, this.compilationUnitSourceLength); + if (end != -1) { + type.setSourceRange(sourceStart, end - sourceStart + 1); + } else { + type.setSourceRange(sourceStart, length); + } + ArrayType subarrayType = (ArrayType) type; + int index = dimensions - 1; + while (index > 0) { + subarrayType = (ArrayType) subarrayType.getComponentType(); + end = retrieveProperRightBracketPosition(index, sourceStart); + subarrayType.setSourceRange(sourceStart, end - sourceStart + 1); + index--; + } + } + } + if (this.resolveBindings) { + this.recordNodes(type, typeReference); + } + return type; + } + +//{ObjectTeams: convert method for OT-specific internal types + // LiftingTypeReference + public LiftingType convertType(LiftingTypeReference typeReference) + { + Name name = convert(typeReference); + LiftingType result = this.ast.newLiftingType(name); + result.setSourceRange(typeReference.sourceStart, typeReference.sourceEnd - typeReference.sourceStart + 1); + + // convert base type + org.eclipse.jdt.internal.compiler.ast.TypeReference baseTypeReference = typeReference.baseReference; + if (baseTypeReference != null) + { + Type baseType = convertType(baseTypeReference); + result.setBaseType(baseType); + } + + // convert role type + org.eclipse.jdt.internal.compiler.ast.TypeReference roleTypeReference = typeReference.roleReference; + if (roleTypeReference != null) + { + Type roleType = convertType(roleTypeReference); + result.setRoleType(roleType); + } + + if (this.resolveBindings) + { + this.recordNodes(result, typeReference); + } + return result; + } + // Type Anchor + public TypeAnchor convertType(TypeAnchorReference anchorRef) { + TypeAnchor result = new TypeAnchor(this.ast); + if (anchorRef.anchor instanceof NameReference) { + result.setPath(convert((NameReference)anchorRef.anchor)); + } else if (anchorRef.anchor instanceof FieldReference) { + throw new InternalCompilerError("Unexpected type "+anchorRef.anchor.getClass()+" for anchor reference "+anchorRef.anchor); + } + int start = anchorRef.sourceStart; + int end = anchorRef.sourceEnd; + result.setSourceRange(start, end-start+1); + return result; + } +//gbr+SH} + + protected Comment createComment(int[] positions) { + // Create comment node + Comment comment = null; + int start = positions[0]; + int end = positions[1]; + if (positions[1]>0) { // Javadoc comments have positive end position + Javadoc docComment = this.docParser.parse(positions); + if (docComment == null) return null; + comment = docComment; + } else { + end = -end; + if (positions[0] == 0) { // we cannot know without testing chars again + if (this.docParser.scanner.source[1] == '/') { + comment = new LineComment(this.ast); + } else { + comment = new BlockComment(this.ast); + } + } + else if (positions[0]>0) { // Block comment have positive start position + comment = new BlockComment(this.ast); + } else { // Line comment have negative start and end position + start = -start; + comment = new LineComment(this.ast); + } + comment.setSourceRange(start, end - start); + } + return comment; + } + + protected Statement createFakeEmptyStatement(org.eclipse.jdt.internal.compiler.ast.Statement statement) { + if (statement == null) return null; + EmptyStatement emptyStatement = new EmptyStatement(this.ast); + emptyStatement.setFlags(emptyStatement.getFlags() | ASTNode.MALFORMED); + int start = statement.sourceStart; + int end = statement.sourceEnd; + emptyStatement.setSourceRange(start, end - start + 1); + return emptyStatement; + } + /** + * @return a new modifier + */ + private Modifier createModifier(ModifierKeyword keyword) { + final Modifier modifier = new Modifier(this.ast); + modifier.setKeyword(keyword); + int start = this.scanner.getCurrentTokenStartPosition(); + int end = this.scanner.getCurrentTokenEndPosition(); + modifier.setSourceRange(start, end - start + 1); + return modifier; + } + + protected InfixExpression.Operator getOperatorFor(int operatorID) { + switch (operatorID) { + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.EQUAL_EQUAL : + return InfixExpression.Operator.EQUALS; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.LESS_EQUAL : + return InfixExpression.Operator.LESS_EQUALS; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.GREATER_EQUAL : + return InfixExpression.Operator.GREATER_EQUALS; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.NOT_EQUAL : + return InfixExpression.Operator.NOT_EQUALS; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.LEFT_SHIFT : + return InfixExpression.Operator.LEFT_SHIFT; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.RIGHT_SHIFT : + return InfixExpression.Operator.RIGHT_SHIFT_SIGNED; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.UNSIGNED_RIGHT_SHIFT : + return InfixExpression.Operator.RIGHT_SHIFT_UNSIGNED; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.OR_OR : + return InfixExpression.Operator.CONDITIONAL_OR; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.AND_AND : + return InfixExpression.Operator.CONDITIONAL_AND; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.PLUS : + return InfixExpression.Operator.PLUS; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.MINUS : + return InfixExpression.Operator.MINUS; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.REMAINDER : + return InfixExpression.Operator.REMAINDER; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.XOR : + return InfixExpression.Operator.XOR; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.AND : + return InfixExpression.Operator.AND; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.MULTIPLY : + return InfixExpression.Operator.TIMES; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.OR : + return InfixExpression.Operator.OR; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.DIVIDE : + return InfixExpression.Operator.DIVIDE; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.GREATER : + return InfixExpression.Operator.GREATER; + case org.eclipse.jdt.internal.compiler.ast.OperatorIds.LESS : + return InfixExpression.Operator.LESS; + } + return null; + } + + protected PrimitiveType.Code getPrimitiveTypeCode(char[] name) { + switch(name[0]) { + case 'i' : + if (name.length == 3 && name[1] == 'n' && name[2] == 't') { + return PrimitiveType.INT; + } + break; + case 'l' : + if (name.length == 4 && name[1] == 'o' && name[2] == 'n' && name[3] == 'g') { + return PrimitiveType.LONG; + } + break; + case 'd' : + if (name.length == 6 + && name[1] == 'o' + && name[2] == 'u' + && name[3] == 'b' + && name[4] == 'l' + && name[5] == 'e') { + return PrimitiveType.DOUBLE; + } + break; + case 'f' : + if (name.length == 5 + && name[1] == 'l' + && name[2] == 'o' + && name[3] == 'a' + && name[4] == 't') { + return PrimitiveType.FLOAT; + } + break; + case 'b' : + if (name.length == 4 + && name[1] == 'y' + && name[2] == 't' + && name[3] == 'e') { + return PrimitiveType.BYTE; + } else + if (name.length == 7 + && name[1] == 'o' + && name[2] == 'o' + && name[3] == 'l' + && name[4] == 'e' + && name[5] == 'a' + && name[6] == 'n') { + return PrimitiveType.BOOLEAN; + } + break; + case 'c' : + if (name.length == 4 + && name[1] == 'h' + && name[2] == 'a' + && name[3] == 'r') { + return PrimitiveType.CHAR; + } + break; + case 's' : + if (name.length == 5 + && name[1] == 'h' + && name[2] == 'o' + && name[3] == 'r' + && name[4] == 't') { + return PrimitiveType.SHORT; + } + break; + case 'v' : + if (name.length == 4 + && name[1] == 'o' + && name[2] == 'i' + && name[3] == 'd') { + return PrimitiveType.VOID; + } + } + return null; // cannot be reached + } + + protected boolean isPrimitiveType(char[] name) { + switch(name[0]) { + case 'i' : + if (name.length == 3 && name[1] == 'n' && name[2] == 't') { + return true; + } + return false; + case 'l' : + if (name.length == 4 && name[1] == 'o' && name[2] == 'n' && name[3] == 'g') { + return true; + } + return false; + case 'd' : + if (name.length == 6 + && name[1] == 'o' + && name[2] == 'u' + && name[3] == 'b' + && name[4] == 'l' + && name[5] == 'e') { + return true; + } + return false; + case 'f' : + if (name.length == 5 + && name[1] == 'l' + && name[2] == 'o' + && name[3] == 'a' + && name[4] == 't') { + return true; + } + return false; + case 'b' : + if (name.length == 4 + && name[1] == 'y' + && name[2] == 't' + && name[3] == 'e') { + return true; + } else + if (name.length == 7 + && name[1] == 'o' + && name[2] == 'o' + && name[3] == 'l' + && name[4] == 'e' + && name[5] == 'a' + && name[6] == 'n') { + return true; + } + return false; + case 'c' : + if (name.length == 4 + && name[1] == 'h' + && name[2] == 'a' + && name[3] == 'r') { + return true; + } + return false; + case 's' : + if (name.length == 5 + && name[1] == 'h' + && name[2] == 'o' + && name[3] == 'r' + && name[4] == 't') { + return true; + } + return false; + case 'v' : + if (name.length == 4 + && name[1] == 'o' + && name[2] == 'i' + && name[3] == 'd') { + return true; + } + return false; + } + return false; + } + + private void lookupForScopes() { + if (this.pendingNameScopeResolution != null) { + for (Iterator iterator = this.pendingNameScopeResolution.iterator(); iterator.hasNext(); ) { + Name name = (Name) iterator.next(); + this.ast.getBindingResolver().recordScope(name, lookupScope(name)); + } + } + if (this.pendingThisExpressionScopeResolution != null) { + for (Iterator iterator = this.pendingThisExpressionScopeResolution.iterator(); iterator.hasNext(); ) { + ThisExpression thisExpression = (ThisExpression) iterator.next(); + this.ast.getBindingResolver().recordScope(thisExpression, lookupScope(thisExpression)); + } + } + + } + + private BlockScope lookupScope(ASTNode node) { + ASTNode currentNode = node; + while(currentNode != null + &&!(currentNode instanceof MethodDeclaration) + && !(currentNode instanceof Initializer) + && !(currentNode instanceof FieldDeclaration) + && !(currentNode instanceof AbstractTypeDeclaration)) { + currentNode = currentNode.getParent(); + } + if (currentNode == null) { + return null; + } + if (currentNode instanceof Initializer) { + Initializer initializer = (Initializer) currentNode; + while(!(currentNode instanceof AbstractTypeDeclaration)) { + currentNode = currentNode.getParent(); + } + if (currentNode instanceof TypeDeclaration + || currentNode instanceof EnumDeclaration + || currentNode instanceof AnnotationTypeDeclaration) { + org.eclipse.jdt.internal.compiler.ast.TypeDeclaration typeDecl = (org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) this.ast.getBindingResolver().getCorrespondingNode(currentNode); + if ((initializer.getModifiers() & Modifier.STATIC) != 0) { + return typeDecl.staticInitializerScope; + } else { + return typeDecl.initializerScope; + } + } + } else if (currentNode instanceof FieldDeclaration) { + FieldDeclaration fieldDeclaration = (FieldDeclaration) currentNode; + while(!(currentNode instanceof AbstractTypeDeclaration)) { + currentNode = currentNode.getParent(); + } + org.eclipse.jdt.internal.compiler.ast.TypeDeclaration typeDecl = (org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) this.ast.getBindingResolver().getCorrespondingNode(currentNode); + if ((fieldDeclaration.getModifiers() & Modifier.STATIC) != 0) { + return typeDecl.staticInitializerScope; + } else { + return typeDecl.initializerScope; + } + } else if (currentNode instanceof AbstractTypeDeclaration) { + org.eclipse.jdt.internal.compiler.ast.TypeDeclaration typeDecl = (org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) this.ast.getBindingResolver().getCorrespondingNode(currentNode); + return typeDecl.initializerScope; + } + AbstractMethodDeclaration abstractMethodDeclaration = (AbstractMethodDeclaration) this.ast.getBindingResolver().getCorrespondingNode(currentNode); + return abstractMethodDeclaration.scope; + } + + protected void recordName(Name name, org.eclipse.jdt.internal.compiler.ast.ASTNode compilerNode) { + if (compilerNode != null) { + recordNodes(name, compilerNode); + if (compilerNode instanceof org.eclipse.jdt.internal.compiler.ast.TypeReference) { + org.eclipse.jdt.internal.compiler.ast.TypeReference typeRef = (org.eclipse.jdt.internal.compiler.ast.TypeReference) compilerNode; + if (name.isQualifiedName()) { + SimpleName simpleName = null; + while (name.isQualifiedName()) { + simpleName = ((QualifiedName) name).getName(); + recordNodes(simpleName, typeRef); + name = ((QualifiedName) name).getQualifier(); + recordNodes(name, typeRef); + } + } + } + } + } + + protected void recordNodes(ASTNode node, org.eclipse.jdt.internal.compiler.ast.ASTNode oldASTNode) { + this.ast.getBindingResolver().store(node, oldASTNode); + } + + protected void recordNodes(org.eclipse.jdt.internal.compiler.ast.Javadoc javadoc, TagElement tagElement) { + Iterator fragments = tagElement.fragments().listIterator(); + while (fragments.hasNext()) { + ASTNode node = (ASTNode) fragments.next(); + if (node.getNodeType() == ASTNode.MEMBER_REF) { + MemberRef memberRef = (MemberRef) node; + Name name = memberRef.getName(); + // get compiler node and record nodes + int start = name.getStartPosition(); + org.eclipse.jdt.internal.compiler.ast.ASTNode compilerNode = javadoc.getNodeStartingAt(start); + if (compilerNode!= null) { + recordNodes(name, compilerNode); + recordNodes(node, compilerNode); + } + // Replace qualifier to have all nodes recorded + if (memberRef.getQualifier() != null) { + org.eclipse.jdt.internal.compiler.ast.TypeReference typeRef = null; + if (compilerNode instanceof JavadocFieldReference) { + org.eclipse.jdt.internal.compiler.ast.Expression expression = ((JavadocFieldReference)compilerNode).receiver; + if (expression instanceof org.eclipse.jdt.internal.compiler.ast.TypeReference) { + typeRef = (org.eclipse.jdt.internal.compiler.ast.TypeReference) expression; + } + } + else if (compilerNode instanceof JavadocMessageSend) { + org.eclipse.jdt.internal.compiler.ast.Expression expression = ((JavadocMessageSend)compilerNode).receiver; + if (expression instanceof org.eclipse.jdt.internal.compiler.ast.TypeReference) { + typeRef = (org.eclipse.jdt.internal.compiler.ast.TypeReference) expression; + } + } + if (typeRef != null) { + recordName(memberRef.getQualifier(), typeRef); + } + } + } else if (node.getNodeType() == ASTNode.METHOD_REF) { + MethodRef methodRef = (MethodRef) node; + Name name = methodRef.getName(); + // get method name start position + int start = methodRef.getStartPosition(); + this.scanner.resetTo(start, start + name.getStartPosition()+name.getLength()); + int token; + try { + nextToken: while((token = this.scanner.getNextToken()) != TerminalTokens.TokenNameEOF && token != TerminalTokens.TokenNameLPAREN) { + if (token == TerminalTokens.TokenNameERROR && this.scanner.currentCharacter == '#') { + start = this.scanner.getCurrentTokenEndPosition()+1; + break nextToken; + } + } + } + catch(InvalidInputException e) { + // ignore + } + // get compiler node and record nodes + org.eclipse.jdt.internal.compiler.ast.ASTNode compilerNode = javadoc.getNodeStartingAt(start); + // record nodes + if (compilerNode != null) { + recordNodes(methodRef, compilerNode); + // get type ref + org.eclipse.jdt.internal.compiler.ast.TypeReference typeRef = null; + if (compilerNode instanceof org.eclipse.jdt.internal.compiler.ast.JavadocAllocationExpression) { + typeRef = ((org.eclipse.jdt.internal.compiler.ast.JavadocAllocationExpression)compilerNode).type; + if (typeRef != null) recordNodes(name, compilerNode); + } + else if (compilerNode instanceof org.eclipse.jdt.internal.compiler.ast.JavadocMessageSend) { + org.eclipse.jdt.internal.compiler.ast.Expression expression = ((org.eclipse.jdt.internal.compiler.ast.JavadocMessageSend)compilerNode).receiver; + if (expression instanceof org.eclipse.jdt.internal.compiler.ast.TypeReference) { + typeRef = (org.eclipse.jdt.internal.compiler.ast.TypeReference) expression; + } + // TODO (frederic) remove following line to fix bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=62650 + recordNodes(name, compilerNode); + } + // record name and qualifier + if (typeRef != null && methodRef.getQualifier() != null) { + recordName(methodRef.getQualifier(), typeRef); + } + } + // Resolve parameters + Iterator parameters = methodRef.parameters().listIterator(); + while (parameters.hasNext()) { + MethodRefParameter param = (MethodRefParameter) parameters.next(); + org.eclipse.jdt.internal.compiler.ast.Expression expression = (org.eclipse.jdt.internal.compiler.ast.Expression) javadoc.getNodeStartingAt(param.getStartPosition()); + if (expression != null) { + recordNodes(param, expression); + if (expression instanceof JavadocArgumentExpression) { + JavadocArgumentExpression argExpr = (JavadocArgumentExpression) expression; + org.eclipse.jdt.internal.compiler.ast.TypeReference typeRef = argExpr.argument.type; + if (this.ast.apiLevel >= AST.JLS3) param.setVarargs(argExpr.argument.isVarArgs()); + recordNodes(param.getType(), typeRef); + if (param.getType().isSimpleType()) { + recordName(((SimpleType)param.getType()).getName(), typeRef); + } else if (param.getType().isArrayType()) { + Type type = ((ArrayType) param.getType()).getElementType(); + recordNodes(type, typeRef); + if (type.isSimpleType()) { + recordName(((SimpleType)type).getName(), typeRef); + } + } + } + } + } + } else if (node.getNodeType() == ASTNode.SIMPLE_NAME || + node.getNodeType() == ASTNode.QUALIFIED_NAME) { + org.eclipse.jdt.internal.compiler.ast.ASTNode compilerNode = javadoc.getNodeStartingAt(node.getStartPosition()); + recordName((Name) node, compilerNode); + } else if (node.getNodeType() == ASTNode.TAG_ELEMENT) { + // resolve member and method references binding + recordNodes(javadoc, (TagElement) node); + } + } + } + + protected void recordPendingNameScopeResolution(Name name) { + if (this.pendingNameScopeResolution == null) { + this.pendingNameScopeResolution = new HashSet(); + } + this.pendingNameScopeResolution.add(name); + } + + protected void recordPendingThisExpressionScopeResolution(ThisExpression thisExpression) { + if (this.pendingThisExpressionScopeResolution == null) { + this.pendingThisExpressionScopeResolution = new HashSet(); + } + this.pendingThisExpressionScopeResolution.add(thisExpression); + } + + /** + * Remove whitespaces and comments before and after the expression. + */ + private void trimWhiteSpacesAndComments(org.eclipse.jdt.internal.compiler.ast.Expression expression) { + int start = expression.sourceStart; + int end = expression.sourceEnd; + int token; + int trimLeftPosition = expression.sourceStart; + int trimRightPosition = expression.sourceEnd; + boolean first = true; + Scanner removeBlankScanner = this.ast.scanner; + try { + removeBlankScanner.setSource(this.compilationUnitSource); + removeBlankScanner.resetTo(start, end); + while (true) { + token = removeBlankScanner.getNextToken(); + switch (token) { + case TerminalTokens.TokenNameCOMMENT_JAVADOC : + case TerminalTokens.TokenNameCOMMENT_LINE : + case TerminalTokens.TokenNameCOMMENT_BLOCK : + if (first) { + trimLeftPosition = removeBlankScanner.currentPosition; + } + break; + case TerminalTokens.TokenNameWHITESPACE : + if (first) { + trimLeftPosition = removeBlankScanner.currentPosition; + } + break; + case TerminalTokens.TokenNameEOF : + expression.sourceStart = trimLeftPosition; + expression.sourceEnd = trimRightPosition; + return; + default : + /* + * if we find something else than a whitespace or a comment, + * then we reset the trimRigthPosition to the expression + * source end. + */ + trimRightPosition = removeBlankScanner.currentPosition - 1; + first = false; + } + } + } catch (InvalidInputException e){ + // ignore + } + } + + /** + * Remove potential trailing comment by settings the source end on the closing parenthesis + */ + protected void removeLeadingAndTrailingCommentsFromLiteral(ASTNode node) { + int start = node.getStartPosition(); + this.scanner.resetTo(start, start + node.getLength()); + int token; + int startPosition = -1; + try { + while((token = this.scanner.getNextToken()) != TerminalTokens.TokenNameEOF) { + switch(token) { + case TerminalTokens.TokenNameIntegerLiteral : + case TerminalTokens.TokenNameFloatingPointLiteral : + case TerminalTokens.TokenNameLongLiteral : + case TerminalTokens.TokenNameDoubleLiteral : + case TerminalTokens.TokenNameCharacterLiteral : + if (startPosition == -1) { + startPosition = this.scanner.startPosition; + } + int end = this.scanner.currentPosition; + node.setSourceRange(startPosition, end - startPosition); + return; + case TerminalTokens.TokenNameMINUS : + startPosition = this.scanner.startPosition; + break; + } + } + } catch(InvalidInputException e) { + // ignore + } + } + + /** + * Remove potential trailing comment by settings the source end on the closing parenthesis + */ + protected void removeTrailingCommentFromExpressionEndingWithAParen(ASTNode node) { + int start = node.getStartPosition(); + this.scanner.resetTo(start, start + node.getLength()); + int token; + int parenCounter = 0; + try { + while((token = this.scanner.getNextToken()) != TerminalTokens.TokenNameEOF) { + switch(token) { + case TerminalTokens.TokenNameLPAREN : + parenCounter++; + break; + case TerminalTokens.TokenNameRPAREN : + parenCounter--; + if (parenCounter == 0) { + int end = this.scanner.currentPosition - 1; + node.setSourceRange(start, end - start + 1); + } + } + } + } catch(InvalidInputException e) { + // ignore + } + } + + /** + * This method is used to retrieve the end position of the block. + * @return int the dimension found, -1 if none + */ + protected int retrieveClosingAngleBracketPosition(int start) { + this.scanner.resetTo(start, this.compilationUnitSourceLength); + this.scanner.returnOnlyGreater = true; + try { + int token; + while ((token = this.scanner.getNextToken()) != TerminalTokens.TokenNameEOF) { + switch(token) { + case TerminalTokens.TokenNameGREATER: + return this.scanner.currentPosition - 1; + default: + return start; + } + } + } catch(InvalidInputException e) { + // ignore + } + this.scanner.returnOnlyGreater = false; + return start; + } + + /** + * This method is used to set the right end position for expression + * statement. The actual AST nodes don't include the trailing semicolon. + * This method fixes the length of the corresponding node. + */ + protected void retrieveColonPosition(ASTNode node) { + int start = node.getStartPosition(); + int length = node.getLength(); + int end = start + length; + this.scanner.resetTo(end, this.compilationUnitSourceLength); + try { + int token; + while ((token = this.scanner.getNextToken()) != TerminalTokens.TokenNameEOF) { + switch(token) { + case TerminalTokens.TokenNameCOLON: + node.setSourceRange(start, this.scanner.currentPosition - start); + return; + } + } + } catch(InvalidInputException e) { + // ignore + } + } + /** + * This method is used to retrieve the start position of the Ellipsis + */ + protected int retrieveEllipsisStartPosition(int start, int end) { + this.scanner.resetTo(start, end); + try { + int token; + while ((token = this.scanner.getNextToken()) != TerminalTokens.TokenNameEOF) { + switch(token) { + case TerminalTokens.TokenNameELLIPSIS: + return this.scanner.startPosition - 1; + } + } + } catch(InvalidInputException e) { + // ignore + } + return -1; + + } + /** + * This method is used to retrieve the end position of the block. + * @return int the dimension found, -1 if none + */ + protected int retrieveEndBlockPosition(int start, int end) { + this.scanner.resetTo(start, end); + int count = 0; + try { + int token; + while ((token = this.scanner.getNextToken()) != TerminalTokens.TokenNameEOF) { + switch(token) { + case TerminalTokens.TokenNameLBRACE://110 + count++; + break; + case TerminalTokens.TokenNameRBRACE://95 + count--; + if (count == 0) { + return this.scanner.currentPosition - 1; + } + } + } + } catch(InvalidInputException e) { + // ignore + } + return -1; + } + + protected int retrieveSemiColonPosition(Expression node) { + int start = node.getStartPosition(); + int length = node.getLength(); + int end = start + length; + this.scanner.resetTo(end, this.compilationUnitSourceLength); + try { + int token; + while ((token = this.scanner.getNextToken()) != TerminalTokens.TokenNameEOF) { + switch(token) { + case TerminalTokens.TokenNameSEMICOLON: + return this.scanner.currentPosition - 1; + } + } + } catch(InvalidInputException e) { + // ignore + } + return -1; + } + + /** + * This method is used to retrieve the ending position for a type declaration when the dimension is right after the type + * name. + * For example: + * int[] i; => return 5, but int i[] => return -1; + * @return int the dimension found + */ + protected int retrieveEndOfDimensionsPosition(int start, int end) { + this.scanner.resetTo(start, end); + int foundPosition = -1; + try { + int token; + while ((token = this.scanner.getNextToken()) != TerminalTokens.TokenNameEOF) { + switch(token) { + case TerminalTokens.TokenNameLBRACKET: + case TerminalTokens.TokenNameCOMMENT_BLOCK: + case TerminalTokens.TokenNameCOMMENT_JAVADOC: + case TerminalTokens.TokenNameCOMMENT_LINE: + break; + case TerminalTokens.TokenNameRBRACKET://166 + foundPosition = this.scanner.currentPosition - 1; + break; + default: + return foundPosition; + } + } + } catch(InvalidInputException e) { + // ignore + } + return foundPosition; + } + + /** + * This method is used to retrieve the position just before the left bracket. + * @return int the dimension found, -1 if none + */ + protected int retrieveEndOfElementTypeNamePosition(int start, int end) { + this.scanner.resetTo(start, end); + try { + int token; + while ((token = this.scanner.getNextToken()) != TerminalTokens.TokenNameEOF) { + switch(token) { + case TerminalTokens.TokenNameIdentifier: + case TerminalTokens.TokenNamebyte: + case TerminalTokens.TokenNamechar: + case TerminalTokens.TokenNamedouble: + case TerminalTokens.TokenNamefloat: + case TerminalTokens.TokenNameint: + case TerminalTokens.TokenNamelong: + case TerminalTokens.TokenNameshort: + case TerminalTokens.TokenNameboolean: + return this.scanner.currentPosition - 1; + } + } + } catch(InvalidInputException e) { + // ignore + } + return -1; + } + + /** + * This method is used to retrieve the position after the right parenthesis. + * @return int the position found + */ + protected int retrieveEndOfRightParenthesisPosition(int start, int end) { + this.scanner.resetTo(start, end); + try { + int token; + while ((token = this.scanner.getNextToken()) != TerminalTokens.TokenNameEOF) { + switch(token) { + case TerminalTokens.TokenNameRPAREN: + return this.scanner.currentPosition; + } + } + } catch(InvalidInputException e) { + // ignore + } + return -1; + } + + /** + * This method is used to retrieve the array dimension declared after the + * name of a local or a field declaration. + * For example: + * int i, j[] = null, k[][] = {{}}; + * It should return 0 for i, 1 for j and 2 for k. + * @return int the dimension found + */ + protected int retrieveExtraDimension(int start, int end) { + this.scanner.resetTo(start, end); + int dimensions = 0; + try { + int token; + while ((token = this.scanner.getNextToken()) != TerminalTokens.TokenNameEOF) { + switch(token) { + case TerminalTokens.TokenNameLBRACKET: + case TerminalTokens.TokenNameCOMMENT_BLOCK: + case TerminalTokens.TokenNameCOMMENT_JAVADOC: + case TerminalTokens.TokenNameCOMMENT_LINE: + break; + case TerminalTokens.TokenNameRBRACKET://166 + dimensions++; + break; + default: + return dimensions; + } + } + } catch(InvalidInputException e) { + // ignore + } + return dimensions; + } + + protected void retrieveIdentifierAndSetPositions(int start, int end, Name name) { + this.scanner.resetTo(start, end); + int token; + try { + while((token = this.scanner.getNextToken()) != TerminalTokens.TokenNameEOF) { + if (token == TerminalTokens.TokenNameIdentifier) { + int startName = this.scanner.startPosition; + int endName = this.scanner.currentPosition - 1; + name.setSourceRange(startName, endName - startName + 1); + return; + } + } + } catch(InvalidInputException e) { + // ignore + } + } + + /** + * This method is used to retrieve the start position of the block. + * @return int the dimension found, -1 if none + */ + protected int retrieveIdentifierEndPosition(int start, int end) { + this.scanner.resetTo(start, end); + try { + int token; + while ((token = this.scanner.getNextToken()) != TerminalTokens.TokenNameEOF) { + switch(token) { +//{ObjectTeams: treat like an Identifier: + case TerminalTokens.TokenNamewhen: +//SH} + case TerminalTokens.TokenNameIdentifier://110 + return this.scanner.getCurrentTokenEndPosition(); + } + } + } catch(InvalidInputException e) { + // ignore + } + return -1; + } + + /** + * This method is used to retrieve position before the next comma or semi-colon. + * @param initializerEnd the given initializer end exclusive + * @return int the position found. + */ + protected int retrieveEndOfPotentialExtendedDimensions(int initializerEnd, int nameEnd, int end) { + this.scanner.resetTo(initializerEnd, end); + boolean hasTokens = false; + int balance = 0; + int pos = initializerEnd > nameEnd ? initializerEnd - 1 : nameEnd; + try { + int token; + while ((token = this.scanner.getNextToken()) != TerminalTokens.TokenNameEOF) { + hasTokens = true; + switch(token) { + case TerminalTokens.TokenNameLBRACE : + case TerminalTokens.TokenNameLBRACKET : + balance++; + break; + case TerminalTokens.TokenNameRBRACKET : + case TerminalTokens.TokenNameRBRACE : + balance --; + pos = this.scanner.currentPosition - 1; + break; + case TerminalTokens.TokenNameCOMMA : + if (balance == 0) return pos; + // case where a missing closing brace doesn't close an array initializer + pos = this.scanner.currentPosition - 1; + break; + case TerminalTokens.TokenNameSEMICOLON : + if (balance == 0) return pos; + return -pos; + } + } + } catch(InvalidInputException e) { + // ignore + } + // no token, we simply return pos as the right position + return hasTokens ? Integer.MIN_VALUE : pos; + } + + protected int retrieveProperRightBracketPosition(int bracketNumber, int start) { + this.scanner.resetTo(start, this.compilationUnitSourceLength); + try { + int token, count = 0; + while ((token = this.scanner.getNextToken()) != TerminalTokens.TokenNameEOF) { + switch(token) { + case TerminalTokens.TokenNameRBRACKET: + count++; + if (count == bracketNumber) { + return this.scanner.currentPosition - 1; + } + } + } + } catch(InvalidInputException e) { + // ignore + } + return -1; + } + + /** + * This method is used to retrieve position before the next right brace or semi-colon. + * @return int the position found. + */ + protected int retrieveRightBraceOrSemiColonPosition(int start, int end) { + this.scanner.resetTo(start, end); + try { + int token; + while ((token = this.scanner.getNextToken()) != TerminalTokens.TokenNameEOF) { + switch(token) { + case TerminalTokens.TokenNameRBRACE : + return this.scanner.currentPosition - 1; + case TerminalTokens.TokenNameSEMICOLON : + return this.scanner.currentPosition - 1; + } + } + } catch(InvalidInputException e) { + // ignore + } + return -1; + } + + /** + * This method is used to retrieve position before the next right brace or semi-colon. + * @return int the position found. + */ + protected int retrieveRightBrace(int start, int end) { + this.scanner.resetTo(start, end); + try { + int token; + while ((token = this.scanner.getNextToken()) != TerminalTokens.TokenNameEOF) { + switch(token) { + case TerminalTokens.TokenNameRBRACE : + return this.scanner.currentPosition - 1; + } + } + } catch(InvalidInputException e) { + // ignore + } + return -1; + } + + /** + * This method is used to retrieve the position of the right bracket. + * @return int the dimension found, -1 if none + */ + protected int retrieveRightBracketPosition(int start, int end) { + this.scanner.resetTo(start, end); + try { + int token; + int balance = 0; + while ((token = this.scanner.getNextToken()) != TerminalTokens.TokenNameEOF) { + switch(token) { + case TerminalTokens.TokenNameLBRACKET : + balance++; + break; + case TerminalTokens.TokenNameRBRACKET : + balance--; + if (balance == 0) return this.scanner.currentPosition - 1; + break; + } + } + } catch(InvalidInputException e) { + // ignore + } + return -1; + } + + /** + * This method is used to retrieve the start position of the block. + * @return int the dimension found, -1 if none + */ + protected int retrieveStartBlockPosition(int start, int end) { + this.scanner.resetTo(start, end); + try { + int token; + while ((token = this.scanner.getNextToken()) != TerminalTokens.TokenNameEOF) { + switch(token) { + case TerminalTokens.TokenNameLBRACE://110 + return this.scanner.startPosition; + } + } + } catch(InvalidInputException e) { + // ignore + } + return -1; + } + + /** + * This method is used to retrieve the starting position of the catch keyword. + * @return int the dimension found, -1 if none + */ + protected int retrieveStartingCatchPosition(int start, int end) { + this.scanner.resetTo(start, end); + try { + int token; + while ((token = this.scanner.getNextToken()) != TerminalTokens.TokenNameEOF) { + switch(token) { + case TerminalTokens.TokenNamecatch://225 + return this.scanner.startPosition; + } + } + } catch(InvalidInputException e) { + // ignore + } + return -1; + } + +//{ObjectTeams: + /** + * This method is used to retrieve the starting position of a '<-' token + * @return int the position found, -1 if none + */ + protected int retrieveBINDINPosition(int start, int end) { + this.scanner.resetTo(start, end); + try { + int token; + while ((token = this.scanner.getNextToken()) != TerminalTokens.TokenNameEOF) { + switch(token) { + case TerminalTokens.TokenNameBINDIN://225 + return this.scanner.startPosition; + } + } + } catch(InvalidInputException e) { + // ignore + } + return -1; + } +// SH} + + public void setAST(AST ast) { +//{ObjectTeams: transfer scanner mode + if (ast.scanner != null && this.scanner != null) + ast.scanner.copyOTFlags(this.scanner); +// SH} + this.ast = ast; + this.docParser = new DocCommentParser(this.ast, this.scanner, this.insideComments); + } + + protected void setModifiers(AnnotationTypeDeclaration typeDecl, org.eclipse.jdt.internal.compiler.ast.TypeDeclaration typeDeclaration) { + this.scanner.resetTo(typeDeclaration.declarationSourceStart, typeDeclaration.sourceStart); + this.setModifiers(typeDecl, typeDeclaration.annotations, typeDeclaration.sourceStart); + } + + protected void setModifiers(AnnotationTypeMemberDeclaration annotationTypeMemberDecl, org.eclipse.jdt.internal.compiler.ast.AnnotationMethodDeclaration annotationTypeMemberDeclaration) { + this.scanner.resetTo(annotationTypeMemberDeclaration.declarationSourceStart, annotationTypeMemberDeclaration.sourceStart); + this.setModifiers(annotationTypeMemberDecl, annotationTypeMemberDeclaration.annotations, annotationTypeMemberDeclaration.sourceStart); + } + + /** + * @param bodyDeclaration + */ + protected void setModifiers(BodyDeclaration bodyDeclaration, org.eclipse.jdt.internal.compiler.ast.Annotation[] annotations, int modifiersEnd) { + this.scanner.tokenizeWhiteSpace = false; + try { + int token; + int indexInAnnotations = 0; + while ((token = this.scanner.getNextToken()) != TerminalTokens.TokenNameEOF) { + IExtendedModifier modifier = null; + switch(token) { + case TerminalTokens.TokenNameabstract: + modifier = createModifier(Modifier.ModifierKeyword.ABSTRACT_KEYWORD); + break; + case TerminalTokens.TokenNamepublic: + modifier = createModifier(Modifier.ModifierKeyword.PUBLIC_KEYWORD); + break; + case TerminalTokens.TokenNamestatic: + modifier = createModifier(Modifier.ModifierKeyword.STATIC_KEYWORD); + break; + case TerminalTokens.TokenNameprotected: + modifier = createModifier(Modifier.ModifierKeyword.PROTECTED_KEYWORD); + break; + case TerminalTokens.TokenNameprivate: + modifier = createModifier(Modifier.ModifierKeyword.PRIVATE_KEYWORD); + break; + case TerminalTokens.TokenNamefinal: + modifier = createModifier(Modifier.ModifierKeyword.FINAL_KEYWORD); + break; +//{ObjectTeams: callin team + case TerminalTokens.TokenNamecallin: + modifier = createModifier(Modifier.ModifierKeyword.CALLIN_KEYWORD); + break; + case TerminalTokens.TokenNameteam: + modifier = createModifier(Modifier.ModifierKeyword.TEAM_KEYWORD); + break; +// SH} + case TerminalTokens.TokenNamenative: + modifier = createModifier(Modifier.ModifierKeyword.NATIVE_KEYWORD); + break; + case TerminalTokens.TokenNamesynchronized: + modifier = createModifier(Modifier.ModifierKeyword.SYNCHRONIZED_KEYWORD); + break; + case TerminalTokens.TokenNametransient: + modifier = createModifier(Modifier.ModifierKeyword.TRANSIENT_KEYWORD); + break; + case TerminalTokens.TokenNamevolatile: + modifier = createModifier(Modifier.ModifierKeyword.VOLATILE_KEYWORD); + break; + case TerminalTokens.TokenNamestrictfp: + modifier = createModifier(Modifier.ModifierKeyword.STRICTFP_KEYWORD); + break; + case TerminalTokens.TokenNameAT : + // we have an annotation + if (annotations != null && indexInAnnotations < annotations.length) { + org.eclipse.jdt.internal.compiler.ast.Annotation annotation = annotations[indexInAnnotations++]; + modifier = convert(annotation); + this.scanner.resetTo(annotation.declarationSourceEnd + 1, modifiersEnd); + } + break; + case TerminalTokens.TokenNameCOMMENT_BLOCK : + case TerminalTokens.TokenNameCOMMENT_LINE : + case TerminalTokens.TokenNameCOMMENT_JAVADOC : + break; + default : + // there is some syntax errors in source code + break; + } + if (modifier != null) { + bodyDeclaration.modifiers().add(modifier); + } + } + } catch(InvalidInputException e) { + // ignore + } + } + + protected void setModifiers(EnumDeclaration enumDeclaration, org.eclipse.jdt.internal.compiler.ast.TypeDeclaration enumDeclaration2) { + this.scanner.resetTo(enumDeclaration2.declarationSourceStart, enumDeclaration2.sourceStart); + this.setModifiers(enumDeclaration, enumDeclaration2.annotations, enumDeclaration2.sourceStart); + } + + protected void setModifiers(EnumConstantDeclaration enumConstantDeclaration, org.eclipse.jdt.internal.compiler.ast.FieldDeclaration fieldDeclaration) { + switch(this.ast.apiLevel) { + case AST.JLS2_INTERNAL : + enumConstantDeclaration.internalSetModifiers(fieldDeclaration.modifiers & ExtraCompilerModifiers.AccJustFlag); + if (fieldDeclaration.annotations != null) { + enumConstantDeclaration.setFlags(enumConstantDeclaration.getFlags() | ASTNode.MALFORMED); + } + break; + case AST.JLS3 : + this.scanner.resetTo(fieldDeclaration.declarationSourceStart, fieldDeclaration.sourceStart); + this.setModifiers(enumConstantDeclaration, fieldDeclaration.annotations, fieldDeclaration.sourceStart); + } + } + + /** + * @param fieldDeclaration + * @param fieldDecl + */ + protected void setModifiers(FieldDeclaration fieldDeclaration, org.eclipse.jdt.internal.compiler.ast.FieldDeclaration fieldDecl) { + switch(this.ast.apiLevel) { + case AST.JLS2_INTERNAL : + fieldDeclaration.internalSetModifiers(fieldDecl.modifiers & ExtraCompilerModifiers.AccJustFlag); + if (fieldDecl.annotations != null) { + fieldDeclaration.setFlags(fieldDeclaration.getFlags() | ASTNode.MALFORMED); + } + break; + case AST.JLS3 : + this.scanner.resetTo(fieldDecl.declarationSourceStart, fieldDecl.sourceStart); + this.setModifiers(fieldDeclaration, fieldDecl.annotations, fieldDecl.sourceStart); + } + } + + /** + * @param initializer + * @param oldInitializer + */ + protected void setModifiers(Initializer initializer, org.eclipse.jdt.internal.compiler.ast.Initializer oldInitializer) { + switch(this.ast.apiLevel) { + case AST.JLS2_INTERNAL: + initializer.internalSetModifiers(oldInitializer.modifiers & ExtraCompilerModifiers.AccJustFlag); + if (oldInitializer.annotations != null) { + initializer.setFlags(initializer.getFlags() | ASTNode.MALFORMED); + } + break; + case AST.JLS3 : + this.scanner.resetTo(oldInitializer.declarationSourceStart, oldInitializer.bodyStart); + this.setModifiers(initializer, oldInitializer.annotations, oldInitializer.bodyStart); + } + } + /** + * @param methodDecl + * @param methodDeclaration + */ + protected void setModifiers(MethodDeclaration methodDecl, AbstractMethodDeclaration methodDeclaration) { + switch(this.ast.apiLevel) { + case AST.JLS2_INTERNAL : + methodDecl.internalSetModifiers(methodDeclaration.modifiers & ExtraCompilerModifiers.AccJustFlag); + if (methodDeclaration.annotations != null) { + methodDecl.setFlags(methodDecl.getFlags() | ASTNode.MALFORMED); + } + break; + case AST.JLS3 : + this.scanner.resetTo(methodDeclaration.declarationSourceStart, methodDeclaration.sourceStart); + this.setModifiers(methodDecl, methodDeclaration.annotations, methodDeclaration.sourceStart); + } + } +//{ObjectTeams: annotations for method mappings: + /** + * @param methodDecl + * @param methodDeclaration + */ + protected void setModifiers(org.eclipse.jdt.core.dom.AbstractMethodMappingDeclaration mappingDecl, + AbstractMethodMappingDeclaration mappingDeclaration) { + switch(this.ast.apiLevel) { + case AST.JLS2_INTERNAL : + if (mappingDeclaration.annotations != null) { + mappingDecl.setFlags(mappingDecl.getFlags() | ASTNode.MALFORMED); + } + break; + case AST.JLS3 : + this.scanner.resetTo(mappingDeclaration.declarationSourceStart, mappingDeclaration.sourceStart); + this.setModifiers(mappingDecl, mappingDeclaration.annotations, mappingDeclaration.sourceStart); + } + } +// SH} + /** + * @param variableDecl + * @param argument + */ + protected void setModifiers(SingleVariableDeclaration variableDecl, Argument argument) { + switch(this.ast.apiLevel) { + case AST.JLS2_INTERNAL : + variableDecl.internalSetModifiers(argument.modifiers & ExtraCompilerModifiers.AccJustFlag); + if (argument.annotations != null) { + variableDecl.setFlags(variableDecl.getFlags() | ASTNode.MALFORMED); + } + break; + case AST.JLS3 : + this.scanner.resetTo(argument.declarationSourceStart, argument.sourceStart); + org.eclipse.jdt.internal.compiler.ast.Annotation[] annotations = argument.annotations; + int indexInAnnotations = 0; + try { + int token; + while ((token = this.scanner.getNextToken()) != TerminalTokens.TokenNameEOF) { + IExtendedModifier modifier = null; + switch(token) { + case TerminalTokens.TokenNameabstract: + modifier = createModifier(Modifier.ModifierKeyword.ABSTRACT_KEYWORD); + break; + case TerminalTokens.TokenNamepublic: + modifier = createModifier(Modifier.ModifierKeyword.PUBLIC_KEYWORD); + break; + case TerminalTokens.TokenNamestatic: + modifier = createModifier(Modifier.ModifierKeyword.STATIC_KEYWORD); + break; + case TerminalTokens.TokenNameprotected: + modifier = createModifier(Modifier.ModifierKeyword.PROTECTED_KEYWORD); + break; + case TerminalTokens.TokenNameprivate: + modifier = createModifier(Modifier.ModifierKeyword.PRIVATE_KEYWORD); + break; + case TerminalTokens.TokenNamefinal: + modifier = createModifier(Modifier.ModifierKeyword.FINAL_KEYWORD); + break; + case TerminalTokens.TokenNamenative: + modifier = createModifier(Modifier.ModifierKeyword.NATIVE_KEYWORD); + break; + case TerminalTokens.TokenNamesynchronized: + modifier = createModifier(Modifier.ModifierKeyword.SYNCHRONIZED_KEYWORD); + break; + case TerminalTokens.TokenNametransient: + modifier = createModifier(Modifier.ModifierKeyword.TRANSIENT_KEYWORD); + break; + case TerminalTokens.TokenNamevolatile: + modifier = createModifier(Modifier.ModifierKeyword.VOLATILE_KEYWORD); + break; + case TerminalTokens.TokenNamestrictfp: + modifier = createModifier(Modifier.ModifierKeyword.STRICTFP_KEYWORD); + break; + case TerminalTokens.TokenNameAT : + // we have an annotation + if (annotations != null && indexInAnnotations < annotations.length) { + org.eclipse.jdt.internal.compiler.ast.Annotation annotation = annotations[indexInAnnotations++]; + modifier = convert(annotation); + this.scanner.resetTo(annotation.declarationSourceEnd + 1, this.compilationUnitSourceLength); + } + break; + case TerminalTokens.TokenNameCOMMENT_BLOCK : + case TerminalTokens.TokenNameCOMMENT_LINE : + case TerminalTokens.TokenNameCOMMENT_JAVADOC : + break; + default : + return; + } + if (modifier != null) { + variableDecl.modifiers().add(modifier); + } + } + } catch(InvalidInputException e) { + // ignore + } + } + } + + protected void setModifiers(SingleVariableDeclaration variableDecl, LocalDeclaration localDeclaration) { + switch(this.ast.apiLevel) { + case AST.JLS2_INTERNAL : + variableDecl.internalSetModifiers(localDeclaration.modifiers & ExtraCompilerModifiers.AccJustFlag); + if (localDeclaration.annotations != null) { + variableDecl.setFlags(variableDecl.getFlags() | ASTNode.MALFORMED); + } + break; + case AST.JLS3 : + this.scanner.resetTo(localDeclaration.declarationSourceStart, localDeclaration.sourceStart); + org.eclipse.jdt.internal.compiler.ast.Annotation[] annotations = localDeclaration.annotations; + int indexInAnnotations = 0; + try { + int token; + while ((token = this.scanner.getNextToken()) != TerminalTokens.TokenNameEOF) { + IExtendedModifier modifier = null; + switch(token) { + case TerminalTokens.TokenNameabstract: + modifier = createModifier(Modifier.ModifierKeyword.ABSTRACT_KEYWORD); + break; + case TerminalTokens.TokenNamepublic: + modifier = createModifier(Modifier.ModifierKeyword.PUBLIC_KEYWORD); + break; + case TerminalTokens.TokenNamestatic: + modifier = createModifier(Modifier.ModifierKeyword.STATIC_KEYWORD); + break; + case TerminalTokens.TokenNameprotected: + modifier = createModifier(Modifier.ModifierKeyword.PROTECTED_KEYWORD); + break; + case TerminalTokens.TokenNameprivate: + modifier = createModifier(Modifier.ModifierKeyword.PRIVATE_KEYWORD); + break; + case TerminalTokens.TokenNamefinal: + modifier = createModifier(Modifier.ModifierKeyword.FINAL_KEYWORD); + break; + case TerminalTokens.TokenNamenative: + modifier = createModifier(Modifier.ModifierKeyword.NATIVE_KEYWORD); + break; + case TerminalTokens.TokenNamesynchronized: + modifier = createModifier(Modifier.ModifierKeyword.SYNCHRONIZED_KEYWORD); + break; + case TerminalTokens.TokenNametransient: + modifier = createModifier(Modifier.ModifierKeyword.TRANSIENT_KEYWORD); + break; + case TerminalTokens.TokenNamevolatile: + modifier = createModifier(Modifier.ModifierKeyword.VOLATILE_KEYWORD); + break; + case TerminalTokens.TokenNamestrictfp: + modifier = createModifier(Modifier.ModifierKeyword.STRICTFP_KEYWORD); + break; + case TerminalTokens.TokenNameAT : + // we have an annotation + if (annotations != null && indexInAnnotations < annotations.length) { + org.eclipse.jdt.internal.compiler.ast.Annotation annotation = annotations[indexInAnnotations++]; + modifier = convert(annotation); + this.scanner.resetTo(annotation.declarationSourceEnd + 1, this.compilationUnitSourceLength); + } + break; + case TerminalTokens.TokenNameCOMMENT_BLOCK : + case TerminalTokens.TokenNameCOMMENT_LINE : + case TerminalTokens.TokenNameCOMMENT_JAVADOC : + break; + default : + return; + } + if (modifier != null) { + variableDecl.modifiers().add(modifier); + } + } + } catch(InvalidInputException e) { + // ignore + } + } + } + + /** + * @param typeDecl + * @param typeDeclaration + */ + protected void setModifiers(TypeDeclaration typeDecl, org.eclipse.jdt.internal.compiler.ast.TypeDeclaration typeDeclaration) { + switch(this.ast.apiLevel) { + case AST.JLS2_INTERNAL : + int modifiers = typeDeclaration.modifiers; + modifiers &= ~ClassFileConstants.AccInterface; // remove AccInterface flags + modifiers &= ExtraCompilerModifiers.AccJustFlag; + typeDecl.internalSetModifiers(modifiers); + if (typeDeclaration.annotations != null) { + typeDecl.setFlags(typeDecl.getFlags() | ASTNode.MALFORMED); + } + break; + case AST.JLS3 : + this.scanner.resetTo(typeDeclaration.declarationSourceStart, typeDeclaration.sourceStart); + this.setModifiers(typeDecl, typeDeclaration.annotations, typeDeclaration.sourceStart); + } + } + + /** + * @param variableDeclarationExpression + * @param localDeclaration + */ + protected void setModifiers(VariableDeclarationExpression variableDeclarationExpression, LocalDeclaration localDeclaration) { + switch(this.ast.apiLevel) { + case AST.JLS2_INTERNAL : + int modifiers = localDeclaration.modifiers & ExtraCompilerModifiers.AccJustFlag; + modifiers &= ~ExtraCompilerModifiers.AccBlankFinal; + variableDeclarationExpression.internalSetModifiers(modifiers); + if (localDeclaration.annotations != null) { + variableDeclarationExpression.setFlags(variableDeclarationExpression.getFlags() | ASTNode.MALFORMED); + } + break; + case AST.JLS3 : + this.scanner.resetTo(localDeclaration.declarationSourceStart, localDeclaration.sourceStart); + org.eclipse.jdt.internal.compiler.ast.Annotation[] annotations = localDeclaration.annotations; + int indexInAnnotations = 0; + try { + int token; + while ((token = this.scanner.getNextToken()) != TerminalTokens.TokenNameEOF) { + IExtendedModifier modifier = null; + switch(token) { + case TerminalTokens.TokenNameabstract: + modifier = createModifier(Modifier.ModifierKeyword.ABSTRACT_KEYWORD); + break; + case TerminalTokens.TokenNamepublic: + modifier = createModifier(Modifier.ModifierKeyword.PUBLIC_KEYWORD); + break; + case TerminalTokens.TokenNamestatic: + modifier = createModifier(Modifier.ModifierKeyword.STATIC_KEYWORD); + break; + case TerminalTokens.TokenNameprotected: + modifier = createModifier(Modifier.ModifierKeyword.PROTECTED_KEYWORD); + break; + case TerminalTokens.TokenNameprivate: + modifier = createModifier(Modifier.ModifierKeyword.PRIVATE_KEYWORD); + break; + case TerminalTokens.TokenNamefinal: + modifier = createModifier(Modifier.ModifierKeyword.FINAL_KEYWORD); + break; + case TerminalTokens.TokenNamenative: + modifier = createModifier(Modifier.ModifierKeyword.NATIVE_KEYWORD); + break; + case TerminalTokens.TokenNamesynchronized: + modifier = createModifier(Modifier.ModifierKeyword.SYNCHRONIZED_KEYWORD); + break; + case TerminalTokens.TokenNametransient: + modifier = createModifier(Modifier.ModifierKeyword.TRANSIENT_KEYWORD); + break; + case TerminalTokens.TokenNamevolatile: + modifier = createModifier(Modifier.ModifierKeyword.VOLATILE_KEYWORD); + break; + case TerminalTokens.TokenNamestrictfp: + modifier = createModifier(Modifier.ModifierKeyword.STRICTFP_KEYWORD); + break; + case TerminalTokens.TokenNameAT : + // we have an annotation + if (annotations != null && indexInAnnotations < annotations.length) { + org.eclipse.jdt.internal.compiler.ast.Annotation annotation = annotations[indexInAnnotations++]; + modifier = convert(annotation); + this.scanner.resetTo(annotation.declarationSourceEnd + 1, this.compilationUnitSourceLength); + } + break; + case TerminalTokens.TokenNameCOMMENT_BLOCK : + case TerminalTokens.TokenNameCOMMENT_LINE : + case TerminalTokens.TokenNameCOMMENT_JAVADOC : + break; + default : + return; + } + if (modifier != null) { + variableDeclarationExpression.modifiers().add(modifier); + } + } + } catch(InvalidInputException e) { + // ignore + } + } + } + + /** + * @param variableDeclarationStatement + * @param localDeclaration + */ + protected void setModifiers(VariableDeclarationStatement variableDeclarationStatement, LocalDeclaration localDeclaration) { + switch(this.ast.apiLevel) { + case AST.JLS2_INTERNAL : + int modifiers = localDeclaration.modifiers & ExtraCompilerModifiers.AccJustFlag; + modifiers &= ~ExtraCompilerModifiers.AccBlankFinal; + variableDeclarationStatement.internalSetModifiers(modifiers); + if (localDeclaration.annotations != null) { + variableDeclarationStatement.setFlags(variableDeclarationStatement.getFlags() | ASTNode.MALFORMED); + } + break; + case AST.JLS3 : + this.scanner.resetTo(localDeclaration.declarationSourceStart, localDeclaration.sourceStart); + org.eclipse.jdt.internal.compiler.ast.Annotation[] annotations = localDeclaration.annotations; + int indexInAnnotations = 0; + try { + int token; + while ((token = this.scanner.getNextToken()) != TerminalTokens.TokenNameEOF) { + IExtendedModifier modifier = null; + switch(token) { + case TerminalTokens.TokenNameabstract: + modifier = createModifier(Modifier.ModifierKeyword.ABSTRACT_KEYWORD); + break; + case TerminalTokens.TokenNamepublic: + modifier = createModifier(Modifier.ModifierKeyword.PUBLIC_KEYWORD); + break; + case TerminalTokens.TokenNamestatic: + modifier = createModifier(Modifier.ModifierKeyword.STATIC_KEYWORD); + break; + case TerminalTokens.TokenNameprotected: + modifier = createModifier(Modifier.ModifierKeyword.PROTECTED_KEYWORD); + break; + case TerminalTokens.TokenNameprivate: + modifier = createModifier(Modifier.ModifierKeyword.PRIVATE_KEYWORD); + break; + case TerminalTokens.TokenNamefinal: + modifier = createModifier(Modifier.ModifierKeyword.FINAL_KEYWORD); + break; + case TerminalTokens.TokenNamenative: + modifier = createModifier(Modifier.ModifierKeyword.NATIVE_KEYWORD); + break; + case TerminalTokens.TokenNamesynchronized: + modifier = createModifier(Modifier.ModifierKeyword.SYNCHRONIZED_KEYWORD); + break; + case TerminalTokens.TokenNametransient: + modifier = createModifier(Modifier.ModifierKeyword.TRANSIENT_KEYWORD); + break; + case TerminalTokens.TokenNamevolatile: + modifier = createModifier(Modifier.ModifierKeyword.VOLATILE_KEYWORD); + break; + case TerminalTokens.TokenNamestrictfp: + modifier = createModifier(Modifier.ModifierKeyword.STRICTFP_KEYWORD); + break; + case TerminalTokens.TokenNameAT : + // we have an annotation + if (annotations != null && indexInAnnotations < annotations.length) { + org.eclipse.jdt.internal.compiler.ast.Annotation annotation = annotations[indexInAnnotations++]; + modifier = convert(annotation); + this.scanner.resetTo(annotation.declarationSourceEnd + 1, this.compilationUnitSourceLength); + } + break; + case TerminalTokens.TokenNameCOMMENT_BLOCK : + case TerminalTokens.TokenNameCOMMENT_LINE : + case TerminalTokens.TokenNameCOMMENT_JAVADOC : + break; + default : + return; + } + if (modifier != null) { + variableDeclarationStatement.modifiers().add(modifier); + } + } + } catch(InvalidInputException e) { + // ignore + } + } + } + + protected QualifiedName setQualifiedNameNameAndSourceRanges(char[][] typeName, long[] positions, org.eclipse.jdt.internal.compiler.ast.ASTNode node) { + int length = typeName.length; + final SimpleName firstToken = new SimpleName(this.ast); + firstToken.internalSetIdentifier(new String(typeName[0])); + firstToken.index = 1; + int start0 = (int)(positions[0]>>>32); + int start = start0; + int end = (int)(positions[0] & 0xFFFFFFFF); + firstToken.setSourceRange(start, end - start + 1); + final SimpleName secondToken = new SimpleName(this.ast); + secondToken.internalSetIdentifier(new String(typeName[1])); + secondToken.index = 2; + start = (int)(positions[1]>>>32); + end = (int)(positions[1] & 0xFFFFFFFF); + secondToken.setSourceRange(start, end - start + 1); + QualifiedName qualifiedName = new QualifiedName(this.ast); + qualifiedName.setQualifier(firstToken); + qualifiedName.setName(secondToken); + if (this.resolveBindings) { + recordNodes(qualifiedName, node); + recordPendingNameScopeResolution(qualifiedName); + recordNodes(firstToken, node); + recordNodes(secondToken, node); + recordPendingNameScopeResolution(firstToken); + recordPendingNameScopeResolution(secondToken); + } + qualifiedName.index = 2; + qualifiedName.setSourceRange(start0, end - start0 + 1); + SimpleName newPart = null; + for (int i = 2; i < length; i++) { + newPart = new SimpleName(this.ast); + newPart.internalSetIdentifier(new String(typeName[i])); + newPart.index = i + 1; + start = (int)(positions[i]>>>32); + end = (int)(positions[i] & 0xFFFFFFFF); + newPart.setSourceRange(start, end - start + 1); + QualifiedName qualifiedName2 = new QualifiedName(this.ast); + qualifiedName2.setQualifier(qualifiedName); + qualifiedName2.setName(newPart); + qualifiedName = qualifiedName2; + qualifiedName.index = newPart.index; + qualifiedName.setSourceRange(start0, end - start0 + 1); + if (this.resolveBindings) { + recordNodes(qualifiedName, node); + recordNodes(newPart, node); + recordPendingNameScopeResolution(qualifiedName); + recordPendingNameScopeResolution(newPart); + } + } + QualifiedName name = qualifiedName; + if (this.resolveBindings) { + recordNodes(name, node); + recordPendingNameScopeResolution(name); + } + return name; + } + + protected QualifiedName setQualifiedNameNameAndSourceRanges(char[][] typeName, long[] positions, int endingIndex, org.eclipse.jdt.internal.compiler.ast.ASTNode node) { + int length = endingIndex + 1; + final SimpleName firstToken = new SimpleName(this.ast); + firstToken.internalSetIdentifier(new String(typeName[0])); + firstToken.index = 1; + int start0 = (int)(positions[0]>>>32); + int start = start0; + int end = (int) positions[0]; + firstToken.setSourceRange(start, end - start + 1); + final SimpleName secondToken = new SimpleName(this.ast); + secondToken.internalSetIdentifier(new String(typeName[1])); + secondToken.index = 2; + start = (int)(positions[1]>>>32); + end = (int) positions[1]; + secondToken.setSourceRange(start, end - start + 1); + QualifiedName qualifiedName = new QualifiedName(this.ast); + qualifiedName.setQualifier(firstToken); + qualifiedName.setName(secondToken); + if (this.resolveBindings) { + recordNodes(qualifiedName, node); + recordPendingNameScopeResolution(qualifiedName); + recordNodes(firstToken, node); + recordNodes(secondToken, node); + recordPendingNameScopeResolution(firstToken); + recordPendingNameScopeResolution(secondToken); + } + qualifiedName.index = 2; + qualifiedName.setSourceRange(start0, end - start0 + 1); + SimpleName newPart = null; + for (int i = 2; i < length; i++) { + newPart = new SimpleName(this.ast); + newPart.internalSetIdentifier(new String(typeName[i])); + newPart.index = i + 1; + start = (int)(positions[i]>>>32); + end = (int) positions[i]; + newPart.setSourceRange(start, end - start + 1); + QualifiedName qualifiedName2 = new QualifiedName(this.ast); + qualifiedName2.setQualifier(qualifiedName); + qualifiedName2.setName(newPart); + qualifiedName = qualifiedName2; + qualifiedName.index = newPart.index; + qualifiedName.setSourceRange(start0, end - start0 + 1); + if (this.resolveBindings) { + recordNodes(qualifiedName, node); + recordNodes(newPart, node); + recordPendingNameScopeResolution(qualifiedName); + recordPendingNameScopeResolution(newPart); + } + } + if (newPart == null && this.resolveBindings) { + recordNodes(qualifiedName, node); + recordPendingNameScopeResolution(qualifiedName); + } + return qualifiedName; + } + + protected void setTypeNameForAnnotation(org.eclipse.jdt.internal.compiler.ast.Annotation compilerAnnotation, Annotation annotation) { + TypeReference typeReference = compilerAnnotation.type; + if (typeReference instanceof QualifiedTypeReference) { + QualifiedTypeReference qualifiedTypeReference = (QualifiedTypeReference) typeReference; + char[][] tokens = qualifiedTypeReference.tokens; + long[] positions = qualifiedTypeReference.sourcePositions; + // QualifiedName + annotation.setTypeName(setQualifiedNameNameAndSourceRanges(tokens, positions, typeReference)); + } else { + SingleTypeReference singleTypeReference = (SingleTypeReference) typeReference; + final SimpleName name = new SimpleName(this.ast); + name.internalSetIdentifier(new String(singleTypeReference.token)); + int start = singleTypeReference.sourceStart; + int end = singleTypeReference.sourceEnd; + name.setSourceRange(start, end - start + 1); + name.index = 1; + annotation.setTypeName(name); + if (this.resolveBindings) { + recordNodes(name, typeReference); + } + } + } + + protected void setTypeForField(FieldDeclaration fieldDeclaration, Type type, int extraDimension) { + if (extraDimension != 0) { + if (type.isArrayType()) { + ArrayType arrayType = (ArrayType) type; + int remainingDimensions = arrayType.getDimensions() - extraDimension; + if (remainingDimensions == 0) { + // the dimensions are after the name so the type of the fieldDeclaration is a simpleType + Type elementType = arrayType.getElementType(); + // cut the child loose from its parent (without creating garbage) + elementType.setParent(null, null); + this.ast.getBindingResolver().updateKey(type, elementType); + fieldDeclaration.setType(elementType); + } else { + int start = type.getStartPosition(); + ArrayType subarrayType = arrayType; + int index = extraDimension; + while (index > 0) { + subarrayType = (ArrayType) subarrayType.getComponentType(); + index--; + } + int end = retrieveProperRightBracketPosition(remainingDimensions, start); + subarrayType.setSourceRange(start, end - start + 1); + // cut the child loose from its parent (without creating garbage) + subarrayType.setParent(null, null); + fieldDeclaration.setType(subarrayType); + updateInnerPositions(subarrayType, remainingDimensions); + this.ast.getBindingResolver().updateKey(type, subarrayType); + } + } else { + fieldDeclaration.setType(type); + } + } else { + if (type.isArrayType()) { + // update positions of the component types of the array type + int dimensions = ((ArrayType) type).getDimensions(); + updateInnerPositions(type, dimensions); + } + fieldDeclaration.setType(type); + } + } + + protected void setTypeForMethodDeclaration(MethodDeclaration methodDeclaration, Type type, int extraDimension) { + if (extraDimension != 0) { + if (type.isArrayType()) { + ArrayType arrayType = (ArrayType) type; + int remainingDimensions = arrayType.getDimensions() - extraDimension; + if (remainingDimensions == 0) { + // the dimensions are after the name so the type of the fieldDeclaration is a simpleType + Type elementType = arrayType.getElementType(); + // cut the child loose from its parent (without creating garbage) + elementType.setParent(null, null); + this.ast.getBindingResolver().updateKey(type, elementType); + switch(this.ast.apiLevel) { + case AST.JLS2_INTERNAL : + methodDeclaration.internalSetReturnType(elementType); + break; + case AST.JLS3 : + methodDeclaration.setReturnType2(elementType); + break; + } + } else { + int start = type.getStartPosition(); + ArrayType subarrayType = arrayType; + int index = extraDimension; + while (index > 0) { + subarrayType = (ArrayType) subarrayType.getComponentType(); + index--; + } + int end = retrieveProperRightBracketPosition(remainingDimensions, start); + subarrayType.setSourceRange(start, end - start + 1); + // cut the child loose from its parent (without creating garbage) + subarrayType.setParent(null, null); + updateInnerPositions(subarrayType, remainingDimensions); + switch(this.ast.apiLevel) { + case AST.JLS2_INTERNAL : + methodDeclaration.internalSetReturnType(subarrayType); + break; + case AST.JLS3 : + methodDeclaration.setReturnType2(subarrayType); + break; + } + this.ast.getBindingResolver().updateKey(type, subarrayType); + } + } else { + switch(this.ast.apiLevel) { + case AST.JLS2_INTERNAL : + methodDeclaration.internalSetReturnType(type); + break; + case AST.JLS3 : + methodDeclaration.setReturnType2(type); + break; + } + } + } else { + switch(this.ast.apiLevel) { + case AST.JLS2_INTERNAL : + methodDeclaration.internalSetReturnType(type); + break; + case AST.JLS3 : + methodDeclaration.setReturnType2(type); + break; + } + } + } + + protected void setTypeForMethodDeclaration(AnnotationTypeMemberDeclaration annotationTypeMemberDeclaration, Type type, int extraDimension) { + annotationTypeMemberDeclaration.setType(type); + } + + protected void setTypeForSingleVariableDeclaration(SingleVariableDeclaration singleVariableDeclaration, Type type, int extraDimension) { + if (extraDimension != 0) { + if (type.isArrayType()) { + ArrayType arrayType = (ArrayType) type; + int remainingDimensions = arrayType.getDimensions() - extraDimension; + if (remainingDimensions == 0) { + // the dimensions are after the name so the type of the fieldDeclaration is a simpleType + Type elementType = arrayType.getElementType(); + // cut the child loose from its parent (without creating garbage) + elementType.setParent(null, null); + this.ast.getBindingResolver().updateKey(type, elementType); + singleVariableDeclaration.setType(elementType); + } else { + int start = type.getStartPosition(); + ArrayType subarrayType = arrayType; + int index = extraDimension; + while (index > 0) { + subarrayType = (ArrayType) subarrayType.getComponentType(); + index--; + } + int end = retrieveProperRightBracketPosition(remainingDimensions, start); + subarrayType.setSourceRange(start, end - start + 1); + // cut the child loose from its parent (without creating garbage) + subarrayType.setParent(null, null); + updateInnerPositions(subarrayType, remainingDimensions); + singleVariableDeclaration.setType(subarrayType); + this.ast.getBindingResolver().updateKey(type, subarrayType); + } + } else { + singleVariableDeclaration.setType(type); + } + } else { + singleVariableDeclaration.setType(type); + } + } + + protected void setTypeForVariableDeclarationExpression(VariableDeclarationExpression variableDeclarationExpression, Type type, int extraDimension) { + if (extraDimension != 0) { + if (type.isArrayType()) { + ArrayType arrayType = (ArrayType) type; + int remainingDimensions = arrayType.getDimensions() - extraDimension; + if (remainingDimensions == 0) { + // the dimensions are after the name so the type of the fieldDeclaration is a simpleType + Type elementType = arrayType.getElementType(); + // cut the child loose from its parent (without creating garbage) + elementType.setParent(null, null); + this.ast.getBindingResolver().updateKey(type, elementType); + variableDeclarationExpression.setType(elementType); + } else { + int start = type.getStartPosition(); + ArrayType subarrayType = arrayType; + int index = extraDimension; + while (index > 0) { + subarrayType = (ArrayType) subarrayType.getComponentType(); + index--; + } + int end = retrieveProperRightBracketPosition(remainingDimensions, start); + subarrayType.setSourceRange(start, end - start + 1); + // cut the child loose from its parent (without creating garbage) + subarrayType.setParent(null, null); + updateInnerPositions(subarrayType, remainingDimensions); + variableDeclarationExpression.setType(subarrayType); + this.ast.getBindingResolver().updateKey(type, subarrayType); + } + } else { + variableDeclarationExpression.setType(type); + } + } else { + variableDeclarationExpression.setType(type); + } + } + + protected void setTypeForVariableDeclarationStatement(VariableDeclarationStatement variableDeclarationStatement, Type type, int extraDimension) { + if (extraDimension != 0) { + if (type.isArrayType()) { + ArrayType arrayType = (ArrayType) type; + int remainingDimensions = arrayType.getDimensions() - extraDimension; + if (remainingDimensions == 0) { + // the dimensions are after the name so the type of the fieldDeclaration is a simpleType + Type elementType = arrayType.getElementType(); + // cut the child loose from its parent (without creating garbage) + elementType.setParent(null, null); + this.ast.getBindingResolver().updateKey(type, elementType); + variableDeclarationStatement.setType(elementType); + } else { + int start = type.getStartPosition(); + ArrayType subarrayType = arrayType; + int index = extraDimension; + while (index > 0) { + subarrayType = (ArrayType) subarrayType.getComponentType(); + index--; + } + int end = retrieveProperRightBracketPosition(remainingDimensions, start); + subarrayType.setSourceRange(start, end - start + 1); + // cut the child loose from its parent (without creating garbage) + subarrayType.setParent(null, null); + updateInnerPositions(subarrayType, remainingDimensions); + variableDeclarationStatement.setType(subarrayType); + this.ast.getBindingResolver().updateKey(type, subarrayType); + } + } else { + variableDeclarationStatement.setType(type); + } + } else { + variableDeclarationStatement.setType(type); + } + } + + protected void updateInnerPositions(Type type, int dimensions) { + if (dimensions > 1) { + // need to set positions for intermediate array type see 42839 + int start = type.getStartPosition(); + Type currentComponentType = ((ArrayType) type).getComponentType(); + int searchedDimension = dimensions - 1; + int rightBracketEndPosition = start; + while (currentComponentType.isArrayType()) { + rightBracketEndPosition = retrieveProperRightBracketPosition(searchedDimension, start); + currentComponentType.setSourceRange(start, rightBracketEndPosition - start + 1); + currentComponentType = ((ArrayType) currentComponentType).getComponentType(); + searchedDimension--; + } + } + } +//{ObjectTeams: convert reused abstract methode declaration + private boolean isReusedAbstractMethodDeclaration(org.eclipse.jdt.internal.compiler.ast.TypeDeclaration typeDeclaration, + org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration methodDeclaration) + { + return (methodDeclaration.isReusingSourceMethod && methodDeclaration.sourceStart > 0 ); + } + + public MethodDeclaration convertReusedAbstractMethodDeclaration( + org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration methodDeclaration) + { + MethodDeclaration methodDecl = (MethodDeclaration) convert(methodDeclaration); + if(methodDecl.ast.apiLevel() == AST.JLS2) + methodDecl.setModifiers(methodDecl.getModifiers() | Modifier.ABSTRACT); + else + methodDecl.modifiers().addAll(ast.newModifiers(methodDecl.getModifiers() | Modifier.ABSTRACT)); + return methodDecl; + } +//jsv} +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTMatcher.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTMatcher.java new file mode 100644 index 000000000..412ec4183 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTMatcher.java @@ -0,0 +1,2843 @@ +/******************************************************************************* + * Copyright (c) 2000, 2009 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 + * $Id: ASTMatcher.java 22567 2009-09-22 16:34:06Z stephan $ + * + * Contributors: + * IBM Corporation - initial API and implementation + * Fraunhofer FIRST - extended API and implementation + * Technical University Berlin - extended API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.dom; + +import java.util.Iterator; +import java.util.List; + +/** + * Concrete superclass and default implementation of an AST subtree matcher. + * <p> + * For example, to compute whether two ASTs subtrees are structurally + * isomorphic, use <code>n1.subtreeMatch(new ASTMatcher(), n2)</code> where + * <code>n1</code> and <code>n2</code> are the AST root nodes of the subtrees. + * </p> + * <p> + * For each different concrete AST node type <i>T</i> there is a + * <code>public boolean match(<i>T</i> node, Object other)</code> method + * that matches the given node against another object (typically another + * AST node, although this is not essential). The default implementations + * provided by this class tests whether the other object is a node of the + * same type with structurally isomorphic child subtrees. For nodes with + * list-valued properties, the child nodes within the list are compared in + * order. For nodes with multiple properties, the child nodes are compared + * in the order that most closely corresponds to the lexical reading order + * of the source program. For instance, for a type declaration node, the + * child ordering is: name, superclass, superinterfaces, and body + * declarations. + * </p> + * <p> + * Subclasses may override (extend or reimplement) some or all of the + * <code>match</code> methods in order to define more specialized subtree + * matchers. + * </p> + * + * @see org.eclipse.jdt.core.dom.ASTNode#subtreeMatch(ASTMatcher, Object) + * @since 2.0 + */ +@SuppressWarnings("unchecked") +public class ASTMatcher { + + /** + * Indicates whether doc tags should be matched. + * @since 3.0 + */ + private boolean matchDocTags; + + /** + * Creates a new AST matcher instance. + * <p> + * For backwards compatibility, the matcher ignores tag + * elements below doc comments by default. Use + * {@link #ASTMatcher(boolean) ASTMatcher(true)} + * for a matcher that compares doc tags by default. + * </p> + */ + public ASTMatcher() { + this(false); + } + + /** + * Creates a new AST matcher instance. + * + * @param matchDocTags <code>true</code> if doc comment tags are + * to be compared by default, and <code>false</code> otherwise + * @see #match(Javadoc,Object) + * @since 3.0 + */ + public ASTMatcher(boolean matchDocTags) { + this.matchDocTags = matchDocTags; + } + + /** + * Returns whether the given lists of AST nodes match pair wise according + * to <code>ASTNode.subtreeMatch</code>. + * <p> + * Note that this is a convenience method, useful for writing recursive + * subtree matchers. + * </p> + * + * @param list1 the first list of AST nodes + * (element type: <code>ASTNode</code>) + * @param list2 the second list of AST nodes + * (element type: <code>ASTNode</code>) + * @return <code>true</code> if the lists have the same number of elements + * and match pair-wise according to <code>ASTNode.subtreeMatch</code> + * @see ASTNode#subtreeMatch(ASTMatcher matcher, Object other) + */ + public final boolean safeSubtreeListMatch(List list1, List list2) { + int size1 = list1.size(); + int size2 = list2.size(); + if (size1 != size2) { + return false; + } + for (Iterator it1 = list1.iterator(), it2 = list2.iterator(); it1.hasNext();) { + ASTNode n1 = (ASTNode) it1.next(); + ASTNode n2 = (ASTNode) it2.next(); + if (!n1.subtreeMatch(this, n2)) { + return false; + } + } + return true; + } + + /** + * Returns whether the given nodes match according to + * <code>AST.subtreeMatch</code>. Returns <code>false</code> if one or + * the other of the nodes are <code>null</code>. Returns <code>true</code> + * if both nodes are <code>null</code>. + * <p> + * Note that this is a convenience method, useful for writing recursive + * subtree matchers. + * </p> + * + * @param node1 the first AST node, or <code>null</code>; must be an + * instance of <code>ASTNode</code> + * @param node2 the second AST node, or <code>null</code>; must be an + * instance of <code>ASTNode</code> + * @return <code>true</code> if the nodes match according + * to <code>AST.subtreeMatch</code> or both are <code>null</code>, and + * <code>false</code> otherwise + * @see ASTNode#subtreeMatch(ASTMatcher, Object) + */ + public final boolean safeSubtreeMatch(Object node1, Object node2) { + if (node1 == null && node2 == null) { + return true; + } + if (node1 == null || node2 == null) { + return false; + } + // N.B. call subtreeMatch even node1==node2!=null + return ((ASTNode) node1).subtreeMatch(this, node2); + } + + /** + * Returns whether the given objects are equal according to + * <code>equals</code>. Returns <code>false</code> if either + * node is <code>null</code>. + * + * @param o1 the first object, or <code>null</code> + * @param o2 the second object, or <code>null</code> + * @return <code>true</code> if the nodes are equal according to + * <code>equals</code> or both <code>null</code>, and + * <code>false</code> otherwise + */ + public static boolean safeEquals(Object o1, Object o2) { + if (o1 == o2) { + return true; + } + if (o1 == null || o2 == null) { + return false; + } + return o1.equals(o2); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + * @since 3.1 + */ + public boolean match(AnnotationTypeDeclaration node, Object other) { + if (!(other instanceof AnnotationTypeDeclaration)) { + return false; + } + AnnotationTypeDeclaration o = (AnnotationTypeDeclaration) other; + // node type added in JLS3 - ignore old JLS2-style modifiers + return (safeSubtreeMatch(node.getJavadoc(), o.getJavadoc()) + && safeSubtreeListMatch(node.modifiers(), o.modifiers()) + && safeSubtreeMatch(node.getName(), o.getName()) + && safeSubtreeListMatch(node.bodyDeclarations(), o.bodyDeclarations())); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + * @since 3.1 + */ + public boolean match(AnnotationTypeMemberDeclaration node, Object other) { + if (!(other instanceof AnnotationTypeMemberDeclaration)) { + return false; + } + AnnotationTypeMemberDeclaration o = (AnnotationTypeMemberDeclaration) other; + // node type added in JLS3 - ignore old JLS2-style modifiers + return (safeSubtreeMatch(node.getJavadoc(), o.getJavadoc()) + && safeSubtreeListMatch(node.modifiers(), o.modifiers()) + && safeSubtreeMatch(node.getType(), o.getType()) + && safeSubtreeMatch(node.getName(), o.getName()) + && safeSubtreeMatch(node.getDefault(), o.getDefault())); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(AnonymousClassDeclaration node, Object other) { + if (!(other instanceof AnonymousClassDeclaration)) { + return false; + } + AnonymousClassDeclaration o = (AnonymousClassDeclaration) other; + return safeSubtreeListMatch(node.bodyDeclarations(), o.bodyDeclarations()); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(ArrayAccess node, Object other) { + if (!(other instanceof ArrayAccess)) { + return false; + } + ArrayAccess o = (ArrayAccess) other; + return ( + safeSubtreeMatch(node.getArray(), o.getArray()) + && safeSubtreeMatch(node.getIndex(), o.getIndex())); + } + + /** + * Returns whether the given node and the other object object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(ArrayCreation node, Object other) { + if (!(other instanceof ArrayCreation)) { + return false; + } + ArrayCreation o = (ArrayCreation) other; + return ( + safeSubtreeMatch(node.getType(), o.getType()) + && safeSubtreeListMatch(node.dimensions(), o.dimensions()) + && safeSubtreeMatch(node.getInitializer(), o.getInitializer())); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(ArrayInitializer node, Object other) { + if (!(other instanceof ArrayInitializer)) { + return false; + } + ArrayInitializer o = (ArrayInitializer) other; + return safeSubtreeListMatch(node.expressions(), o.expressions()); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(ArrayType node, Object other) { + if (!(other instanceof ArrayType)) { + return false; + } + ArrayType o = (ArrayType) other; + return safeSubtreeMatch(node.getComponentType(), o.getComponentType()); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(AssertStatement node, Object other) { + if (!(other instanceof AssertStatement)) { + return false; + } + AssertStatement o = (AssertStatement) other; + return ( + safeSubtreeMatch(node.getExpression(), o.getExpression()) + && safeSubtreeMatch(node.getMessage(), o.getMessage())); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(Assignment node, Object other) { + if (!(other instanceof Assignment)) { + return false; + } + Assignment o = (Assignment) other; + return ( + node.getOperator().equals(o.getOperator()) + && safeSubtreeMatch(node.getLeftHandSide(), o.getLeftHandSide()) + && safeSubtreeMatch(node.getRightHandSide(), o.getRightHandSide())); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(Block node, Object other) { + if (!(other instanceof Block)) { + return false; + } + Block o = (Block) other; + return safeSubtreeListMatch(node.statements(), o.statements()); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type. Subclasses may override + * this method as needed. + * </p> + * <p>Note: {@link LineComment} and {@link BlockComment} nodes are + * not considered part of main structure of the AST. This method will + * only be called if a client goes out of their way to visit this + * kind of node explicitly. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + * @since 3.0 + */ + public boolean match(BlockComment node, Object other) { + if (!(other instanceof BlockComment)) { + return false; + } + return true; + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(BooleanLiteral node, Object other) { + if (!(other instanceof BooleanLiteral)) { + return false; + } + BooleanLiteral o = (BooleanLiteral) other; + return node.booleanValue() == o.booleanValue(); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(BreakStatement node, Object other) { + if (!(other instanceof BreakStatement)) { + return false; + } + BreakStatement o = (BreakStatement) other; + return safeSubtreeMatch(node.getLabel(), o.getLabel()); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(CastExpression node, Object other) { + if (!(other instanceof CastExpression)) { + return false; + } + CastExpression o = (CastExpression) other; + return ( + safeSubtreeMatch(node.getType(), o.getType()) + && safeSubtreeMatch(node.getExpression(), o.getExpression())); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(CatchClause node, Object other) { + if (!(other instanceof CatchClause)) { + return false; + } + CatchClause o = (CatchClause) other; + return ( + safeSubtreeMatch(node.getException(), o.getException()) + && safeSubtreeMatch(node.getBody(), o.getBody())); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(CharacterLiteral node, Object other) { + if (!(other instanceof CharacterLiteral)) { + return false; + } + CharacterLiteral o = (CharacterLiteral) other; + return safeEquals(node.getEscapedValue(), o.getEscapedValue()); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(ClassInstanceCreation node, Object other) { + if (!(other instanceof ClassInstanceCreation)) { + return false; + } + ClassInstanceCreation o = (ClassInstanceCreation) other; + int level = node.getAST().apiLevel; + if (level == AST.JLS2_INTERNAL) { + if (!safeSubtreeMatch(node.internalGetName(), o.internalGetName())) { + return false; + } + } + if (level >= AST.JLS3) { + if (!safeSubtreeListMatch(node.typeArguments(), o.typeArguments())) { + return false; + } + if (!safeSubtreeMatch(node.getType(), o.getType())) { + return false; + } + } + return + safeSubtreeMatch(node.getExpression(), o.getExpression()) + && safeSubtreeListMatch(node.arguments(), o.arguments()) + && safeSubtreeMatch( + node.getAnonymousClassDeclaration(), + o.getAnonymousClassDeclaration()); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(CompilationUnit node, Object other) { + if (!(other instanceof CompilationUnit)) { + return false; + } + CompilationUnit o = (CompilationUnit) other; + return ( + safeSubtreeMatch(node.getPackage(), o.getPackage()) + && safeSubtreeListMatch(node.imports(), o.imports()) + && safeSubtreeListMatch(node.types(), o.types())); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(ConditionalExpression node, Object other) { + if (!(other instanceof ConditionalExpression)) { + return false; + } + ConditionalExpression o = (ConditionalExpression) other; + return ( + safeSubtreeMatch(node.getExpression(), o.getExpression()) + && safeSubtreeMatch(node.getThenExpression(), o.getThenExpression()) + && safeSubtreeMatch(node.getElseExpression(), o.getElseExpression())); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(ConstructorInvocation node, Object other) { + if (!(other instanceof ConstructorInvocation)) { + return false; + } + ConstructorInvocation o = (ConstructorInvocation) other; + if (node.getAST().apiLevel >= AST.JLS3) { + if (!safeSubtreeListMatch(node.typeArguments(), o.typeArguments())) { + return false; + } + } + return safeSubtreeListMatch(node.arguments(), o.arguments()); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(ContinueStatement node, Object other) { + if (!(other instanceof ContinueStatement)) { + return false; + } + ContinueStatement o = (ContinueStatement) other; + return safeSubtreeMatch(node.getLabel(), o.getLabel()); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(DoStatement node, Object other) { + if (!(other instanceof DoStatement)) { + return false; + } + DoStatement o = (DoStatement) other; + return ( + safeSubtreeMatch(node.getExpression(), o.getExpression()) + && safeSubtreeMatch(node.getBody(), o.getBody())); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(EmptyStatement node, Object other) { + if (!(other instanceof EmptyStatement)) { + return false; + } + return true; + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + * @since 3.1 + */ + public boolean match(EnhancedForStatement node, Object other) { + if (!(other instanceof EnhancedForStatement)) { + return false; + } + EnhancedForStatement o = (EnhancedForStatement) other; + return ( + safeSubtreeMatch(node.getParameter(), o.getParameter()) + && safeSubtreeMatch(node.getExpression(), o.getExpression()) + && safeSubtreeMatch(node.getBody(), o.getBody())); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + * @since 3.1 + */ + public boolean match(EnumConstantDeclaration node, Object other) { + if (!(other instanceof EnumConstantDeclaration)) { + return false; + } + EnumConstantDeclaration o = (EnumConstantDeclaration) other; + return ( + safeSubtreeMatch(node.getJavadoc(), o.getJavadoc()) + && safeSubtreeListMatch(node.modifiers(), o.modifiers()) + && safeSubtreeMatch(node.getName(), o.getName()) + && safeSubtreeListMatch(node.arguments(), o.arguments()) + && safeSubtreeMatch( + node.getAnonymousClassDeclaration(), + o.getAnonymousClassDeclaration())); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + * @since 3.1 + */ + public boolean match(EnumDeclaration node, Object other) { + if (!(other instanceof EnumDeclaration)) { + return false; + } + EnumDeclaration o = (EnumDeclaration) other; + return ( + safeSubtreeMatch(node.getJavadoc(), o.getJavadoc()) + && safeSubtreeListMatch(node.modifiers(), o.modifiers()) + && safeSubtreeMatch(node.getName(), o.getName()) + && safeSubtreeListMatch(node.superInterfaceTypes(), o.superInterfaceTypes()) + && safeSubtreeListMatch(node.enumConstants(), o.enumConstants()) + && safeSubtreeListMatch( + node.bodyDeclarations(), + o.bodyDeclarations())); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(ExpressionStatement node, Object other) { + if (!(other instanceof ExpressionStatement)) { + return false; + } + ExpressionStatement o = (ExpressionStatement) other; + return safeSubtreeMatch(node.getExpression(), o.getExpression()); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(FieldAccess node, Object other) { + if (!(other instanceof FieldAccess)) { + return false; + } + FieldAccess o = (FieldAccess) other; + return ( + safeSubtreeMatch(node.getExpression(), o.getExpression()) + && safeSubtreeMatch(node.getName(), o.getName())); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(FieldDeclaration node, Object other) { + if (!(other instanceof FieldDeclaration)) { + return false; + } + FieldDeclaration o = (FieldDeclaration) other; + int level = node.getAST().apiLevel; + if (level == AST.JLS2_INTERNAL) { + if (node.getModifiers() != o.getModifiers()) { + return false; + } + } + if (level >= AST.JLS3) { + if (!safeSubtreeListMatch(node.modifiers(), o.modifiers())) { + return false; + } + } + return + safeSubtreeMatch(node.getJavadoc(), o.getJavadoc()) + && safeSubtreeMatch(node.getType(), o.getType()) + && safeSubtreeListMatch(node.fragments(), o.fragments()); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(ForStatement node, Object other) { + if (!(other instanceof ForStatement)) { + return false; + } + ForStatement o = (ForStatement) other; + return ( + safeSubtreeListMatch(node.initializers(), o.initializers()) + && safeSubtreeMatch(node.getExpression(), o.getExpression()) + && safeSubtreeListMatch(node.updaters(), o.updaters()) + && safeSubtreeMatch(node.getBody(), o.getBody())); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(IfStatement node, Object other) { + if (!(other instanceof IfStatement)) { + return false; + } + IfStatement o = (IfStatement) other; + return ( + safeSubtreeMatch(node.getExpression(), o.getExpression()) + && safeSubtreeMatch(node.getThenStatement(), o.getThenStatement()) + && safeSubtreeMatch(node.getElseStatement(), o.getElseStatement())); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(ImportDeclaration node, Object other) { + if (!(other instanceof ImportDeclaration)) { + return false; + } + ImportDeclaration o = (ImportDeclaration) other; + if (node.getAST().apiLevel >= AST.JLS3) { + if (node.isStatic() != o.isStatic()) { + return false; + } + } + return ( + safeSubtreeMatch(node.getName(), o.getName()) + && node.isOnDemand() == o.isOnDemand()); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(InfixExpression node, Object other) { + if (!(other instanceof InfixExpression)) { + return false; + } + InfixExpression o = (InfixExpression) other; + // be careful not to trigger lazy creation of extended operand lists + if (node.hasExtendedOperands() && o.hasExtendedOperands()) { + if (!safeSubtreeListMatch(node.extendedOperands(), o.extendedOperands())) { + return false; + } + } + if (node.hasExtendedOperands() != o.hasExtendedOperands()) { + return false; + } + return ( + node.getOperator().equals(o.getOperator()) + && safeSubtreeMatch(node.getLeftOperand(), o.getLeftOperand()) + && safeSubtreeMatch(node.getRightOperand(), o.getRightOperand())); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(InstanceofExpression node, Object other) { + if (!(other instanceof InstanceofExpression)) { + return false; + } + InstanceofExpression o = (InstanceofExpression) other; + return ( + safeSubtreeMatch(node.getLeftOperand(), o.getLeftOperand()) + && safeSubtreeMatch(node.getRightOperand(), o.getRightOperand())); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(Initializer node, Object other) { + if (!(other instanceof Initializer)) { + return false; + } + Initializer o = (Initializer) other; + int level = node.getAST().apiLevel; + if (level == AST.JLS2_INTERNAL) { + if (node.getModifiers() != o.getModifiers()) { + return false; + } + } + if (level >= AST.JLS3) { + if (!safeSubtreeListMatch(node.modifiers(), o.modifiers())) { + return false; + } + } + return ( + safeSubtreeMatch(node.getJavadoc(), o.getJavadoc()) + && safeSubtreeMatch(node.getBody(), o.getBody())); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * Unlike other node types, the behavior of the default + * implementation is controlled by a constructor-supplied + * parameter {@link #ASTMatcher(boolean) ASTMatcher(boolean)} + * which is <code>false</code> if not specified. + * When this parameter is <code>true</code>, the implementation + * tests whether the other object is also a <code>Javadoc</code> + * with structurally isomorphic child subtrees; the comment string + * (<code>Javadoc.getComment()</code>) is ignored. + * Conversely, when the parameter is <code>false</code>, the + * implementation tests whether the other object is also a + * <code>Javadoc</code> with exactly the same comment string; + * the tag elements ({@link Javadoc#tags() Javadoc.tags} are + * ignored. Subclasses may reimplement. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + * @see #ASTMatcher() + * @see #ASTMatcher(boolean) + */ + public boolean match(Javadoc node, Object other) { + if (!(other instanceof Javadoc)) { + return false; + } + Javadoc o = (Javadoc) other; + if (this.matchDocTags) { + return safeSubtreeListMatch(node.tags(), o.tags()); + } else { + return compareDeprecatedComment(node, o); + } + } + + /** + * Return whether the deprecated comment strings of the given java doc are equals. + * <p> + * Note the only purpose of this method is to hide deprecated warnings. + * @deprecated mark deprecated to hide deprecated usage + */ + private boolean compareDeprecatedComment(Javadoc first, Javadoc second) { + if (first.getAST().apiLevel == AST.JLS2_INTERNAL) { + return safeEquals(first.getComment(), second.getComment()); + } else { + return true; + } + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(LabeledStatement node, Object other) { + if (!(other instanceof LabeledStatement)) { + return false; + } + LabeledStatement o = (LabeledStatement) other; + return ( + safeSubtreeMatch(node.getLabel(), o.getLabel()) + && safeSubtreeMatch(node.getBody(), o.getBody())); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type. Subclasses may override + * this method as needed. + * </p> + * <p>Note: {@link LineComment} and {@link BlockComment} nodes are + * not considered part of main structure of the AST. This method will + * only be called if a client goes out of their way to visit this + * kind of node explicitly. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + * @since 3.0 + */ + public boolean match(LineComment node, Object other) { + if (!(other instanceof LineComment)) { + return false; + } + return true; + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + * @since 3.1 + */ + public boolean match(MarkerAnnotation node, Object other) { + if (!(other instanceof MarkerAnnotation)) { + return false; + } + MarkerAnnotation o = (MarkerAnnotation) other; + return safeSubtreeMatch(node.getTypeName(), o.getTypeName()); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + * @since 3.0 + */ + public boolean match(MemberRef node, Object other) { + if (!(other instanceof MemberRef)) { + return false; + } + MemberRef o = (MemberRef) other; + return ( + safeSubtreeMatch(node.getQualifier(), o.getQualifier()) + && safeSubtreeMatch(node.getName(), o.getName())); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + * @since 3.1 + */ + public boolean match(MemberValuePair node, Object other) { + if (!(other instanceof MemberValuePair)) { + return false; + } + MemberValuePair o = (MemberValuePair) other; + return (safeSubtreeMatch(node.getName(), o.getName()) + && safeSubtreeMatch(node.getValue(), o.getValue())); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + * @since 3.0 + */ + public boolean match(MethodRef node, Object other) { + if (!(other instanceof MethodRef)) { + return false; + } + MethodRef o = (MethodRef) other; + return ( + safeSubtreeMatch(node.getQualifier(), o.getQualifier()) + && safeSubtreeMatch(node.getName(), o.getName()) + && safeSubtreeListMatch(node.parameters(), o.parameters())); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + * @since 3.0 + */ + public boolean match(MethodRefParameter node, Object other) { + if (!(other instanceof MethodRefParameter)) { + return false; + } + MethodRefParameter o = (MethodRefParameter) other; + int level = node.getAST().apiLevel; + if (level >= AST.JLS3) { + if (node.isVarargs() != o.isVarargs()) { + return false; + } + } + return ( + safeSubtreeMatch(node.getType(), o.getType()) + && safeSubtreeMatch(node.getName(), o.getName())); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * <p> + * Note that extra array dimensions are compared since they are an + * important part of the method declaration. + * </p> + * <p> + * Note that the method return types are compared even for constructor + * declarations. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(MethodDeclaration node, Object other) { + if (!(other instanceof MethodDeclaration)) { + return false; + } + MethodDeclaration o = (MethodDeclaration) other; + int level = node.getAST().apiLevel; + if (level == AST.JLS2_INTERNAL) { + if (node.getModifiers() != o.getModifiers()) { + return false; + } + if (!safeSubtreeMatch(node.internalGetReturnType(), o.internalGetReturnType())) { + return false; + } + } + if (level >= AST.JLS3) { + if (!safeSubtreeListMatch(node.modifiers(), o.modifiers())) { + return false; + } + if (!safeSubtreeMatch(node.getReturnType2(), o.getReturnType2())) { + return false; + } + // n.b. compare type parameters even for constructors + if (!safeSubtreeListMatch(node.typeParameters(), o.typeParameters())) { + return false; + } + } + return ((node.isConstructor() == o.isConstructor()) + && safeSubtreeMatch(node.getJavadoc(), o.getJavadoc()) + && safeSubtreeMatch(node.getName(), o.getName()) + // n.b. compare return type even for constructors + && safeSubtreeListMatch(node.parameters(), o.parameters()) + && node.getExtraDimensions() == o.getExtraDimensions() + && safeSubtreeListMatch(node.thrownExceptions(), o.thrownExceptions()) +//{ObjectTeams: + && safeSubtreeMatch(node.getGuardPredicate(), o.getGuardPredicate()) +// SH} + && safeSubtreeMatch(node.getBody(), o.getBody())); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(MethodInvocation node, Object other) { + if (!(other instanceof MethodInvocation)) { + return false; + } + MethodInvocation o = (MethodInvocation) other; + if (node.getAST().apiLevel >= AST.JLS3) { + if (!safeSubtreeListMatch(node.typeArguments(), o.typeArguments())) { + return false; + } + } + return ( + safeSubtreeMatch(node.getExpression(), o.getExpression()) + && safeSubtreeMatch(node.getName(), o.getName()) + && safeSubtreeListMatch(node.arguments(), o.arguments())); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + * @since 3.1 + */ + public boolean match(Modifier node, Object other) { + if (!(other instanceof Modifier)) { + return false; + } + Modifier o = (Modifier) other; + return (node.getKeyword() == o.getKeyword()); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + * @since 3.1 + */ + public boolean match(NormalAnnotation node, Object other) { + if (!(other instanceof NormalAnnotation)) { + return false; + } + NormalAnnotation o = (NormalAnnotation) other; + return (safeSubtreeMatch(node.getTypeName(), o.getTypeName()) + && safeSubtreeListMatch(node.values(), o.values())); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(NullLiteral node, Object other) { + if (!(other instanceof NullLiteral)) { + return false; + } + return true; + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(NumberLiteral node, Object other) { + if (!(other instanceof NumberLiteral)) { + return false; + } + NumberLiteral o = (NumberLiteral) other; + return safeEquals(node.getToken(), o.getToken()); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(PackageDeclaration node, Object other) { + if (!(other instanceof PackageDeclaration)) { + return false; + } + PackageDeclaration o = (PackageDeclaration) other; + if (node.getAST().apiLevel >= AST.JLS3) { + if (!safeSubtreeMatch(node.getJavadoc(), o.getJavadoc())) { + return false; + } + if (!safeSubtreeListMatch(node.annotations(), o.annotations())) { + return false; + } + } + return safeSubtreeMatch(node.getName(), o.getName()); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + * @since 3.1 + */ + public boolean match(ParameterizedType node, Object other) { + if (!(other instanceof ParameterizedType)) { + return false; + } + ParameterizedType o = (ParameterizedType) other; + return safeSubtreeMatch(node.getType(), o.getType()) + && safeSubtreeListMatch(node.typeArguments(), o.typeArguments()); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(ParenthesizedExpression node, Object other) { + if (!(other instanceof ParenthesizedExpression)) { + return false; + } + ParenthesizedExpression o = (ParenthesizedExpression) other; + return safeSubtreeMatch(node.getExpression(), o.getExpression()); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(PostfixExpression node, Object other) { + if (!(other instanceof PostfixExpression)) { + return false; + } + PostfixExpression o = (PostfixExpression) other; + return ( + node.getOperator().equals(o.getOperator()) + && safeSubtreeMatch(node.getOperand(), o.getOperand())); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(PrefixExpression node, Object other) { + if (!(other instanceof PrefixExpression)) { + return false; + } + PrefixExpression o = (PrefixExpression) other; + return ( + node.getOperator().equals(o.getOperator()) + && safeSubtreeMatch(node.getOperand(), o.getOperand())); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(PrimitiveType node, Object other) { + if (!(other instanceof PrimitiveType)) { + return false; + } + PrimitiveType o = (PrimitiveType) other; + return (node.getPrimitiveTypeCode() == o.getPrimitiveTypeCode()); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(QualifiedName node, Object other) { + if (!(other instanceof QualifiedName)) { + return false; + } + QualifiedName o = (QualifiedName) other; + return ( + safeSubtreeMatch(node.getQualifier(), o.getQualifier()) + && safeSubtreeMatch(node.getName(), o.getName())); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + * @since 3.1 + */ + public boolean match(QualifiedType node, Object other) { + if (!(other instanceof QualifiedType)) { + return false; + } + QualifiedType o = (QualifiedType) other; + return ( + safeSubtreeMatch(node.getQualifier(), o.getQualifier()) + && safeSubtreeMatch(node.getName(), o.getName())); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(ReturnStatement node, Object other) { + if (!(other instanceof ReturnStatement)) { + return false; + } + ReturnStatement o = (ReturnStatement) other; + return safeSubtreeMatch(node.getExpression(), o.getExpression()); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(SimpleName node, Object other) { + if (!(other instanceof SimpleName)) { + return false; + } + SimpleName o = (SimpleName) other; + return node.getIdentifier().equals(o.getIdentifier()); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(SimpleType node, Object other) { + if (!(other instanceof SimpleType)) { + return false; + } + SimpleType o = (SimpleType) other; + return safeSubtreeMatch(node.getName(), o.getName()); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + * @since 3.1 + */ + public boolean match(SingleMemberAnnotation node, Object other) { + if (!(other instanceof SingleMemberAnnotation)) { + return false; + } + SingleMemberAnnotation o = (SingleMemberAnnotation) other; + return (safeSubtreeMatch(node.getTypeName(), o.getTypeName()) + && safeSubtreeMatch(node.getValue(), o.getValue())); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * <p> + * Note that extra array dimensions and the variable arity flag + * are compared since they are both important parts of the declaration. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(SingleVariableDeclaration node, Object other) { + if (!(other instanceof SingleVariableDeclaration)) { + return false; + } + SingleVariableDeclaration o = (SingleVariableDeclaration) other; + int level = node.getAST().apiLevel; + if (level == AST.JLS2_INTERNAL) { + if (node.getModifiers() != o.getModifiers()) { + return false; + } + } + if (level >= AST.JLS3) { + if (!safeSubtreeListMatch(node.modifiers(), o.modifiers())) { + return false; + } + if (node.isVarargs() != o.isVarargs()) { + return false; + } + } + return + safeSubtreeMatch(node.getType(), o.getType()) + && safeSubtreeMatch(node.getName(), o.getName()) + && node.getExtraDimensions() == o.getExtraDimensions() + && safeSubtreeMatch(node.getInitializer(), o.getInitializer()); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(StringLiteral node, Object other) { + if (!(other instanceof StringLiteral)) { + return false; + } + StringLiteral o = (StringLiteral) other; + return safeEquals(node.getEscapedValue(), o.getEscapedValue()); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(SuperConstructorInvocation node, Object other) { + if (!(other instanceof SuperConstructorInvocation)) { + return false; + } + SuperConstructorInvocation o = (SuperConstructorInvocation) other; + if (node.getAST().apiLevel >= AST.JLS3) { + if (!safeSubtreeListMatch(node.typeArguments(), o.typeArguments())) { + return false; + } + } + return ( + safeSubtreeMatch(node.getExpression(), o.getExpression()) + && safeSubtreeListMatch(node.arguments(), o.arguments())); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(SuperFieldAccess node, Object other) { + if (!(other instanceof SuperFieldAccess)) { + return false; + } + SuperFieldAccess o = (SuperFieldAccess) other; + return ( + safeSubtreeMatch(node.getName(), o.getName()) + && safeSubtreeMatch(node.getQualifier(), o.getQualifier())); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(SuperMethodInvocation node, Object other) { + if (!(other instanceof SuperMethodInvocation)) { + return false; + } + SuperMethodInvocation o = (SuperMethodInvocation) other; + if (node.getAST().apiLevel >= AST.JLS3) { + if (!safeSubtreeListMatch(node.typeArguments(), o.typeArguments())) { + return false; + } + } + return ( + safeSubtreeMatch(node.getQualifier(), o.getQualifier()) + && safeSubtreeMatch(node.getName(), o.getName()) + && safeSubtreeListMatch(node.arguments(), o.arguments())); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(SwitchCase node, Object other) { + if (!(other instanceof SwitchCase)) { + return false; + } + SwitchCase o = (SwitchCase) other; + return safeSubtreeMatch(node.getExpression(), o.getExpression()); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(SwitchStatement node, Object other) { + if (!(other instanceof SwitchStatement)) { + return false; + } + SwitchStatement o = (SwitchStatement) other; + return ( + safeSubtreeMatch(node.getExpression(), o.getExpression()) + && safeSubtreeListMatch(node.statements(), o.statements())); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(SynchronizedStatement node, Object other) { + if (!(other instanceof SynchronizedStatement)) { + return false; + } + SynchronizedStatement o = (SynchronizedStatement) other; + return ( + safeSubtreeMatch(node.getExpression(), o.getExpression()) + && safeSubtreeMatch(node.getBody(), o.getBody())); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + * @since 3.0 + */ + public boolean match(TagElement node, Object other) { + if (!(other instanceof TagElement)) { + return false; + } + TagElement o = (TagElement) other; + return ( + safeEquals(node.getTagName(), o.getTagName()) + && safeSubtreeListMatch(node.fragments(), o.fragments())); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + * @since 3.0 + */ + public boolean match(TextElement node, Object other) { + if (!(other instanceof TextElement)) { + return false; + } + TextElement o = (TextElement) other; + return safeEquals(node.getText(), o.getText()); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(ThisExpression node, Object other) { + if (!(other instanceof ThisExpression)) { + return false; + } + ThisExpression o = (ThisExpression) other; + return safeSubtreeMatch(node.getQualifier(), o.getQualifier()); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(ThrowStatement node, Object other) { + if (!(other instanceof ThrowStatement)) { + return false; + } + ThrowStatement o = (ThrowStatement) other; + return safeSubtreeMatch(node.getExpression(), o.getExpression()); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(TryStatement node, Object other) { + if (!(other instanceof TryStatement)) { + return false; + } + TryStatement o = (TryStatement) other; + return ( + safeSubtreeMatch(node.getBody(), o.getBody()) + && safeSubtreeListMatch(node.catchClauses(), o.catchClauses()) + && safeSubtreeMatch(node.getFinally(), o.getFinally())); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(TypeDeclaration node, Object other) { + if (!(other instanceof TypeDeclaration)) { + return false; + } + TypeDeclaration o = (TypeDeclaration) other; + int level = node.getAST().apiLevel; + if (level == AST.JLS2_INTERNAL) { + if (node.getModifiers() != o.getModifiers()) { + return false; + } + if (!safeSubtreeMatch(node.internalGetSuperclass(), o.internalGetSuperclass())) { + return false; + } + if (!safeSubtreeListMatch(node.internalSuperInterfaces(), o.internalSuperInterfaces())) { + return false; + } + } + if (level >= AST.JLS3) { + if (!safeSubtreeListMatch(node.modifiers(), o.modifiers())) { + return false; + } + if (!safeSubtreeListMatch(node.typeParameters(), o.typeParameters())) { + return false; + } + if (!safeSubtreeMatch(node.getSuperclassType(), o.getSuperclassType())) { + return false; + } + if (!safeSubtreeListMatch(node.superInterfaceTypes(), o.superInterfaceTypes())) { + return false; + } +//{ObjectTeams: + if (node.isTeam() != o.isTeam()) + return false; + if (node.isRole() != o.isRole()) + return false; + if (!safeSubtreeListMatch(node.precedences(), o.precedences())) + return false; +// SH} + } + return ( + (node.isInterface() == o.isInterface()) + && safeSubtreeMatch(node.getJavadoc(), o.getJavadoc()) + && safeSubtreeMatch(node.getName(), o.getName()) + && safeSubtreeListMatch(node.bodyDeclarations(), o.bodyDeclarations())); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(TypeDeclarationStatement node, Object other) { + if (!(other instanceof TypeDeclarationStatement)) { + return false; + } + TypeDeclarationStatement o = (TypeDeclarationStatement) other; + return safeSubtreeMatch(node.getDeclaration(), o.getDeclaration()); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(TypeLiteral node, Object other) { + if (!(other instanceof TypeLiteral)) { + return false; + } + TypeLiteral o = (TypeLiteral) other; + return safeSubtreeMatch(node.getType(), o.getType()); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + * @since 3.1 + */ + public boolean match(TypeParameter node, Object other) { + if (!(other instanceof TypeParameter)) { + return false; + } + TypeParameter o = (TypeParameter) other; + return safeSubtreeMatch(node.getName(), o.getName()) +//{ObjectTeams: value parameter & <B base R>: + && node.isValueParameter() == o.isValueParameter() + && node.hasBaseBound() == o.hasBaseBound() +// SH} + && safeSubtreeListMatch(node.typeBounds(), o.typeBounds()); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(VariableDeclarationExpression node, Object other) { + if (!(other instanceof VariableDeclarationExpression)) { + return false; + } + VariableDeclarationExpression o = (VariableDeclarationExpression) other; + int level = node.getAST().apiLevel; + if (level == AST.JLS2_INTERNAL) { + if (node.getModifiers() != o.getModifiers()) { + return false; + } + } + if (level >= AST.JLS3) { + if (!safeSubtreeListMatch(node.modifiers(), o.modifiers())) { + return false; + } + } + return safeSubtreeMatch(node.getType(), o.getType()) + && safeSubtreeListMatch(node.fragments(), o.fragments()); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * <p> + * Note that extra array dimensions are compared since they are an + * important part of the type of the variable. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(VariableDeclarationFragment node, Object other) { + if (!(other instanceof VariableDeclarationFragment)) { + return false; + } + VariableDeclarationFragment o = (VariableDeclarationFragment) other; + return safeSubtreeMatch(node.getName(), o.getName()) + && node.getExtraDimensions() == o.getExtraDimensions() + && safeSubtreeMatch(node.getInitializer(), o.getInitializer()); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(VariableDeclarationStatement node, Object other) { + if (!(other instanceof VariableDeclarationStatement)) { + return false; + } + VariableDeclarationStatement o = (VariableDeclarationStatement) other; + int level = node.getAST().apiLevel; + if (level == AST.JLS2_INTERNAL) { + if (node.getModifiers() != o.getModifiers()) { + return false; + } + } + if (level >= AST.JLS3) { + if (!safeSubtreeListMatch(node.modifiers(), o.modifiers())) { + return false; + } + } + return safeSubtreeMatch(node.getType(), o.getType()) + && safeSubtreeListMatch(node.fragments(), o.fragments()); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(WhileStatement node, Object other) { + if (!(other instanceof WhileStatement)) { + return false; + } + WhileStatement o = (WhileStatement) other; + return ( + safeSubtreeMatch(node.getExpression(), o.getExpression()) + && safeSubtreeMatch(node.getBody(), o.getBody())); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + * @since 3.1 + */ + public boolean match(WildcardType node, Object other) { + if (!(other instanceof WildcardType)) { + return false; + } + WildcardType o = (WildcardType) other; + return node.isUpperBound() == o.isUpperBound() + && safeSubtreeMatch(node.getBound(), o.getBound()); + } + +//{ObjectTeams: match methods for OT-specific types + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(MethodSpec node, Object other) + { + if (!(other instanceof MethodSpec)) + { + return false; + } + MethodSpec otherMethodSpec = (MethodSpec) other; + int level = node.getAST().apiLevel; + + if (level == AST.JLS3) + { + if (!safeSubtreeMatch(node.getReturnType2(), + otherMethodSpec.getReturnType2())) + { + return false; + } + } + if (level == AST.JLS2) + { + node.setFlags(ASTNode.MALFORMED); + } + return safeSubtreeMatch(node.getName(), otherMethodSpec.getName()) + && safeSubtreeListMatch(node.parameters(), otherMethodSpec.parameters()) + && safeSubtreeListMatch(node.typeParameters(), otherMethodSpec.typeParameters()) + && (node.hasSignature() == otherMethodSpec.hasSignature()) + && (node.hasCovariantReturn() == otherMethodSpec.hasCovariantReturn()); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(CallinMappingDeclaration node, Object other) + { + if (!(other instanceof CallinMappingDeclaration)) + { + return false; + } + CallinMappingDeclaration node2 = (CallinMappingDeclaration)other; + int level = node.getAST().apiLevel; + + if (level == AST.JLS3) + { + if (!safeSubtreeMatch(node.getName(), node2.getName())) + { + return false; + } + if (node.getModifiers() != node2.getModifiers()) + { + return false; + } + if (!safeSubtreeMatch(node.getRoleMappingElement(), + node2.getRoleMappingElement())) + { + return false; + } + if (!safeSubtreeListMatch(node.getBaseMappingElements(), + node2.getBaseMappingElements())) + { + return false; + } + if (!safeSubtreeListMatch(node.getParameterMappings(), + node2.getParameterMappings())) + { + return false; + } + } + if (level >= AST.JLS2) + { + node.setFlags(ASTNode.MALFORMED); + } + return safeSubtreeMatch(node.getJavadoc(), node2.getJavadoc()) + && safeSubtreeMatch(node.getGuardPredicate(), node2.getGuardPredicate()); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(CalloutMappingDeclaration node, Object other) + { + if (!(other instanceof CalloutMappingDeclaration)) + { + return false; + } + CalloutMappingDeclaration otherCalloutMappingDecl = (CalloutMappingDeclaration) other; + int level = node.getAST().apiLevel; + + if (level == AST.JLS3) + { + if (!safeSubtreeMatch(node.getRoleMappingElement(), + otherCalloutMappingDecl.getRoleMappingElement())) + { + return false; + } + if (!safeSubtreeMatch(node.getBaseMappingElement(), + otherCalloutMappingDecl.getBaseMappingElement())) + { + return false; + } + if (!safeSubtreeListMatch(node.getParameterMappings(), + otherCalloutMappingDecl.getParameterMappings())) + { + return false; + } + } + if (level >= AST.JLS2) + { + node.setFlags(ASTNode.MALFORMED); + } + return (safeSubtreeMatch(node.getJavadoc(), otherCalloutMappingDecl.getJavadoc()) + && (node.isCalloutOverride() == otherCalloutMappingDecl.isCalloutOverride()) + && (node.hasSignature() == otherCalloutMappingDecl.hasSignature())); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(LiftingType node, Object other) + { + if (!(other instanceof LiftingType)) + { + return false; + } + LiftingType otherType = (LiftingType) other; + return (safeSubtreeMatch(node.getName(), otherType.getName()) + && safeSubtreeMatch(node.getBaseType(), otherType.getBaseType()) + && safeSubtreeMatch(node.getRoleType(), otherType.getRoleType()) + ); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(TypeAnchor node, Object other) + { + if (!(other instanceof TypeAnchor)) + { + return false; + } + TypeAnchor otherType = (TypeAnchor) other; + return safeSubtreeMatch(node.getPath(), otherType.getPath()); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(WithinStatement node, Object other) + { + if (!(other instanceof WithinStatement)) + { + return false; + } + WithinStatement node2 = (WithinStatement) other; + + return (safeSubtreeMatch(node.getBody(), node2.getBody()) + && safeSubtreeMatch(node.getTeamExpression(), node2.getTeamExpression()) + ); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(TSuperMessageSend node, Object other) + { + if (!(other instanceof TSuperMessageSend)) + { + return false; + } + TSuperMessageSend otherExpression = (TSuperMessageSend) other; + return ( safeSubtreeMatch(node.getName(), otherExpression.getName()) + && safeSubtreeListMatch(node.getArguments(), otherExpression.getArguments()) + ); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(TSuperConstructorInvocation node, Object other) + { + if (!(other instanceof TSuperConstructorInvocation)) + { + return false; + } + TSuperConstructorInvocation otherExpression = (TSuperConstructorInvocation) other; + return (safeSubtreeListMatch(node.getArguments(), + otherExpression.getArguments()) + ); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(BaseCallMessageSend node, Object other) + { + if (!(other instanceof BaseCallMessageSend)) + { + return false; + } + BaseCallMessageSend otherExpression = (BaseCallMessageSend) other; + return ( safeSubtreeMatch(node.getName(), otherExpression.getName()) + && safeSubtreeListMatch(node.getArguments(), otherExpression.getArguments()) + ); + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(BaseConstructorInvocation node, Object other) + { + if (!(other instanceof BaseConstructorInvocation)) + { + return false; + } + BaseConstructorInvocation node2 = (BaseConstructorInvocation) other; + return safeSubtreeListMatch(node.getArguments(), node2.getArguments()); + + } + + /** + * Returns whether the given node and the other object match. + * <p> + * The default implementation provided by this class tests whether the + * other object is a node of the same type with structurally isomorphic + * child subtrees. Subclasses may override this method as needed. + * </p> + * + * @param node the node + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match or the other object has a + * different node type or is <code>null</code> + */ + public boolean match(org.eclipse.jdt.core.dom.ParameterMapping node, Object other) { + if (!(other instanceof org.eclipse.jdt.core.dom.ParameterMapping)) + { + return false; + } + org.eclipse.jdt.core.dom.ParameterMapping otherParameterMapping = + (org.eclipse.jdt.core.dom.ParameterMapping) other; + return safeSubtreeMatch(node.getExpression(), otherParameterMapping.getExpression()); + } + + public boolean match(org.eclipse.jdt.core.dom.RoleTypeDeclaration node, Object other) { + if (!(other instanceof org.eclipse.jdt.core.dom.RoleTypeDeclaration)) + { + return false; + } + + RoleTypeDeclaration o = (RoleTypeDeclaration) other; + int level = node.getAST().apiLevel; + if (level == AST.JLS2) + { + if (node.getModifiers() != o.getModifiers()) + { + return false; + } + if (!safeSubtreeMatch(node.getSuperclass(), o.getSuperclass())) + { + return false; + } + if (!safeSubtreeMatch(node.getBaseClass(), o.getBaseClass())) + { + return false; + } + if (!safeSubtreeMatch(node.getTeamClass(), o.getTeamClass())) + { + return false; + } + if (!safeSubtreeListMatch(node.superInterfaces(), o.superInterfaces())) + { + return false; + } + } + if (level >= AST.JLS3) { + if (!safeSubtreeListMatch(node.modifiers(), o.modifiers())) + { + return false; + } + if (!safeSubtreeListMatch(node.typeParameters(), o.typeParameters())) + { + return false; + } + if (!safeSubtreeMatch(node.getSuperclassType(), o.getSuperclassType())) + { + return false; + } + if (!safeSubtreeMatch(node.getBaseClassType(), o.getBaseClassType())) + { + return false; + } + if (!safeSubtreeMatch(node.getTeamClassType(), o.getTeamClassType())) + { + return false; + } + if (!safeSubtreeListMatch(node.superInterfaceTypes(), o.superInterfaceTypes())) + { + return false; + } + if (node.isTeam() != o.isTeam()) + return false; + if (node.isRoleFile() != o.isRoleFile()) + return false; + if (!safeSubtreeListMatch(node.precedences(), o.precedences())) + return false; + } + return ( + (node.isInterface() == o.isInterface()) + && safeSubtreeMatch(node.getJavadoc(), o.getJavadoc()) + && safeSubtreeMatch(node.getName(), o.getName()) + && safeSubtreeMatch(node.getGuardPredicate(), o.getGuardPredicate()) + && safeSubtreeListMatch(node.bodyDeclarations(), o.bodyDeclarations())); + } + + public boolean match(FieldAccessSpec node, Object other) { + if (!(other instanceof FieldAccessSpec)) { + return false; + } + FieldAccessSpec otherFieldAccessSpec = (FieldAccessSpec) other; + + if (!safeSubtreeMatch(node.getFieldType(), otherFieldAccessSpec.getFieldType())) { + return false; + } + + return ((node.hasSignature() == otherFieldAccessSpec.hasSignature()) + && safeSubtreeMatch(node.getName(), otherFieldAccessSpec.getName())); + } + + public boolean match(PrecedenceDeclaration node, Object other) { + if (!(other instanceof PrecedenceDeclaration)) { + return false; + } + PrecedenceDeclaration otherPrecedence = (PrecedenceDeclaration) other; + + return safeSubtreeMatch(node.elements(), otherPrecedence.elements()); + } + + public boolean match(GuardPredicateDeclaration node, Object other) { + if (!(other instanceof GuardPredicateDeclaration)) + return false; + GuardPredicateDeclaration otherPredicate = (GuardPredicateDeclaration)other; + return + node.isBase() == otherPredicate.isBase() + && safeSubtreeMatch(node.getExpression(), otherPredicate.getExpression()); + } +//gbr, jsv, SH} +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTNode.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTNode.java new file mode 100644 index 000000000..974d92f15 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTNode.java @@ -0,0 +1,2880 @@ +/******************************************************************************* + * Copyright (c) 2000, 2009 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 + * $Id: ASTNode.java 22573 2009-09-23 10:49:24Z stephan $ + * + * Contributors: + * IBM Corporation - initial API and implementation + * Fraunhofer FIRST - extended API and implementation + * Technical University Berlin - extended API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.AbstractList; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.eclipse.jdt.internal.core.dom.NaiveASTFlattener; + +/** + * Abstract superclass of all Abstract Syntax Tree (AST) node types. + * <p> + * An AST node represents a Java source code construct, such + * as a name, type, expression, statement, or declaration. + * </p> + * <p> + * Each AST node belongs to a unique AST instance, called the owning AST. + * The children of an AST node always have the same owner as their parent node. + * If a node from one AST is to be added to a different AST, the subtree must + * be cloned first to ensure that the added nodes have the correct owning AST. + * </p> + * <p> + * When an AST node is part of an AST, it has a unique parent node. + * Clients can navigate upwards, from child to parent, as well as downwards, + * from parent to child. Newly created nodes are unparented. When an + * unparented node is set as a child of a node (using a + * <code>set<i>CHILD</i></code> method), its parent link is set automatically + * and the parent link of the former child is set to <code>null</code>. + * For nodes with properties that include a list of children (for example, + * <code>Block</code> whose <code>statements</code> property is a list + * of statements), adding or removing an element to/for the list property + * automatically updates the parent links. These lists support the + * <code>List.set</code> method; however, the constraint that the same + * node cannot appear more than once means that this method cannot be used + * to swap elements without first removing the node. + * </p> + * <p> + * ASTs must not contain cycles. All operations that could create a cycle + * detect this possibility and fail. + * </p> + * <p> + * ASTs do not contain "holes" (missing subtrees). If a node is required to + * have a certain property, a syntactically plausible initial value is + * always supplied. + * </p> + * <p> + * The hierarchy of AST node types has some convenient groupings marked + * by abstract superclasses: + * <ul> + * <li>expressions - <code>Expression</code></li> + * <li>names - <code>Name</code> (a sub-kind of expression)</li> + * <li>statements - <code>Statement</code></li> + * <li>types - <code>Type</code></li> + * <li>type body declarations - <code>BodyDeclaration</code></li> + * </ul> + * </p> + * <p> + * Abstract syntax trees may be hand constructed by clients, using the + * <code>new<i>TYPE</i></code> factory methods (see <code>AST</code>) to + * create new nodes, and the various <code>set<i>CHILD</i></code> methods + * to connect them together. + * </p> + * <p> + * The class {@link ASTParser} parses a string + * containing a Java source code and returns an abstract syntax tree + * for it. The resulting nodes carry source ranges relating the node back to + * the original source characters. The source range covers the construct + * as a whole. + * </p> + * <p> + * Each AST node carries bit flags, which may convey additional information about + * the node. For instance, the parser uses a flag to indicate a syntax error. + * Newly created nodes have no flags set. + * </p> + * <p> + * Each AST node is capable of carrying an open-ended collection of + * client-defined properties. Newly created nodes have none. + * <code>getProperty</code> and <code>setProperty</code> are used to access + * these properties. + * </p> + * <p> + * AST nodes are thread-safe for readers provided there are no active writers. + * If one thread is modifying an AST, including creating new nodes or cloning + * existing ones, it is <b>not</b> safe for another thread to read, visit, + * write, create, or clone <em>any</em> of the nodes on the same AST. + * When synchronization is required, consider using the common AST + * object that owns the node; that is, use + * <code>synchronize (node.getAST()) {...}</code>. + * </p> + * <p> + * ASTs also support the visitor pattern; see the class <code>ASTVisitor</code> + * for details. The <code>NodeFinder</code> class can be used to find a specific + * node inside a tree. + * </p> + * <p> + * Compilation units created by <code>ASTParser</code> from a + * source document can be serialized after arbitrary modifications + * with minimal loss of original formatting. See + * {@link CompilationUnit#recordModifications()} for details. + * See also {@link org.eclipse.jdt.core.dom.rewrite.ASTRewrite} for + * an alternative way to describe and serialize changes to a + * read-only AST. + * </p> + * + * @see ASTParser + * @see ASTVisitor + * @see NodeFinder + * @since 2.0 + * @noextend This class is not intended to be subclassed by clients. + */ +public abstract class ASTNode { + /* + * INSTRUCTIONS FOR ADDING NEW CONCRETE AST NODE TYPES + * + * There are several things that need to be changed when a + * new concrete AST node type (call it "FooBar"): + * + * 1. Create the FooBar AST node type class. + * The most effective way to do this is to copy a similar + * existing concrete node class to get a template that + * includes all the framework methods that must be implemented. + * + * 2. Add node type constant ASTNode.FOO_BAR. + * Node constants are numbered consecutively. Add the + * constant after the existing ones. + * + * 3. Add entry to ASTNode.nodeClassForType(int). + * + * 4. Add AST.newFooBar() factory method. + * + * 5. Add ASTVisitor.visit(FooBar) and endVisit(FooBar) methods. + * + * 6. Add ASTMatcher.match(FooBar,Object) method. + * + * 7. Ensure that SimpleName.isDeclaration() covers FooBar + * nodes if required. + * + * 8. Add NaiveASTFlattener.visit(FooBar) method to illustrate + * how these nodes should be serialized. + * + * 9. Update the AST test suites. + * + * The next steps are to update AST.parse* to start generating + * the new type of nodes, and ASTRewrite to serialize them back out. + */ + + /** + * Node type constant indicating a node of type + * <code>AnonymousClassDeclaration</code>. + * @see AnonymousClassDeclaration + */ + public static final int ANONYMOUS_CLASS_DECLARATION = 1; + + /** + * Node type constant indicating a node of type + * <code>ArrayAccess</code>. + * @see ArrayAccess + */ + public static final int ARRAY_ACCESS = 2; + + /** + * Node type constant indicating a node of type + * <code>ArrayCreation</code>. + * @see ArrayCreation + */ + public static final int ARRAY_CREATION = 3; + + /** + * Node type constant indicating a node of type + * <code>ArrayInitializer</code>. + * @see ArrayInitializer + */ + public static final int ARRAY_INITIALIZER = 4; + + /** + * Node type constant indicating a node of type + * <code>ArrayType</code>. + * @see ArrayType + */ + public static final int ARRAY_TYPE = 5; + + /** + * Node type constant indicating a node of type + * <code>AssertStatement</code>. + * @see AssertStatement + */ + public static final int ASSERT_STATEMENT = 6; + + /** + * Node type constant indicating a node of type + * <code>Assignment</code>. + * @see Assignment + */ + public static final int ASSIGNMENT = 7; + + /** + * Node type constant indicating a node of type + * <code>Block</code>. + * @see Block + */ + public static final int BLOCK = 8; + + /** + * Node type constant indicating a node of type + * <code>BooleanLiteral</code>. + * @see BooleanLiteral + */ + public static final int BOOLEAN_LITERAL = 9; + + /** + * Node type constant indicating a node of type + * <code>BreakStatement</code>. + * @see BreakStatement + */ + public static final int BREAK_STATEMENT = 10; + + /** + * Node type constant indicating a node of type + * <code>CastExpression</code>. + * @see CastExpression + */ + public static final int CAST_EXPRESSION = 11; + + /** + * Node type constant indicating a node of type + * <code>CatchClause</code>. + * @see CatchClause + */ + public static final int CATCH_CLAUSE = 12; + + /** + * Node type constant indicating a node of type + * <code>CharacterLiteral</code>. + * @see CharacterLiteral + */ + public static final int CHARACTER_LITERAL = 13; + + /** + * Node type constant indicating a node of type + * <code>ClassInstanceCreation</code>. + * @see ClassInstanceCreation + */ + public static final int CLASS_INSTANCE_CREATION = 14; + + /** + * Node type constant indicating a node of type + * <code>CompilationUnit</code>. + * @see CompilationUnit + */ + public static final int COMPILATION_UNIT = 15; + + /** + * Node type constant indicating a node of type + * <code>ConditionalExpression</code>. + * @see ConditionalExpression + */ + public static final int CONDITIONAL_EXPRESSION = 16; + + /** + * Node type constant indicating a node of type + * <code>ConstructorInvocation</code>. + * @see ConstructorInvocation + */ + public static final int CONSTRUCTOR_INVOCATION = 17; + + /** + * Node type constant indicating a node of type + * <code>ContinueStatement</code>. + * @see ContinueStatement + */ + public static final int CONTINUE_STATEMENT = 18; + + /** + * Node type constant indicating a node of type + * <code>DoStatement</code>. + * @see DoStatement + */ + public static final int DO_STATEMENT = 19; + + /** + * Node type constant indicating a node of type + * <code>EmptyStatement</code>. + * @see EmptyStatement + */ + public static final int EMPTY_STATEMENT = 20; + + /** + * Node type constant indicating a node of type + * <code>ExpressionStatement</code>. + * @see ExpressionStatement + */ + public static final int EXPRESSION_STATEMENT = 21; + + /** + * Node type constant indicating a node of type + * <code>FieldAccess</code>. + * @see FieldAccess + */ + public static final int FIELD_ACCESS = 22; + + /** + * Node type constant indicating a node of type + * <code>FieldDeclaration</code>. + * @see FieldDeclaration + */ + public static final int FIELD_DECLARATION = 23; + + /** + * Node type constant indicating a node of type + * <code>ForStatement</code>. + * @see ForStatement + */ + public static final int FOR_STATEMENT = 24; + + /** + * Node type constant indicating a node of type + * <code>IfStatement</code>. + * @see IfStatement + */ + public static final int IF_STATEMENT = 25; + + /** + * Node type constant indicating a node of type + * <code>ImportDeclaration</code>. + * @see ImportDeclaration + */ + public static final int IMPORT_DECLARATION = 26; + + /** + * Node type constant indicating a node of type + * <code>InfixExpression</code>. + * @see InfixExpression + */ + public static final int INFIX_EXPRESSION = 27; + + /** + * Node type constant indicating a node of type + * <code>Initializer</code>. + * @see Initializer + */ + public static final int INITIALIZER = 28; + + /** + * Node type constant indicating a node of type + * <code>Javadoc</code>. + * @see Javadoc + */ + public static final int JAVADOC = 29; + + /** + * Node type constant indicating a node of type + * <code>LabeledStatement</code>. + * @see LabeledStatement + */ + public static final int LABELED_STATEMENT = 30; + + /** + * Node type constant indicating a node of type + * <code>MethodDeclaration</code>. + * @see MethodDeclaration + */ + public static final int METHOD_DECLARATION = 31; + + /** + * Node type constant indicating a node of type + * <code>MethodInvocation</code>. + * @see MethodInvocation + */ + public static final int METHOD_INVOCATION = 32; + + /** + * Node type constant indicating a node of type + * <code>NullLiteral</code>. + * @see NullLiteral + */ + public static final int NULL_LITERAL = 33; + + /** + * Node type constant indicating a node of type + * <code>NumberLiteral</code>. + * @see NumberLiteral + */ + public static final int NUMBER_LITERAL = 34; + + /** + * Node type constant indicating a node of type + * <code>PackageDeclaration</code>. + * @see PackageDeclaration + */ + public static final int PACKAGE_DECLARATION = 35; + + /** + * Node type constant indicating a node of type + * <code>ParenthesizedExpression</code>. + * @see ParenthesizedExpression + */ + public static final int PARENTHESIZED_EXPRESSION = 36; + + /** + * Node type constant indicating a node of type + * <code>PostfixExpression</code>. + * @see PostfixExpression + */ + public static final int POSTFIX_EXPRESSION = 37; + + /** + * Node type constant indicating a node of type + * <code>PrefixExpression</code>. + * @see PrefixExpression + */ + public static final int PREFIX_EXPRESSION = 38; + + /** + * Node type constant indicating a node of type + * <code>PrimitiveType</code>. + * @see PrimitiveType + */ + public static final int PRIMITIVE_TYPE = 39; + + /** + * Node type constant indicating a node of type + * <code>QualifiedName</code>. + * @see QualifiedName + */ + public static final int QUALIFIED_NAME = 40; + + /** + * Node type constant indicating a node of type + * <code>ReturnStatement</code>. + * @see ReturnStatement + */ + public static final int RETURN_STATEMENT = 41; + + /** + * Node type constant indicating a node of type + * <code>SimpleName</code>. + * @see SimpleName + */ + public static final int SIMPLE_NAME = 42; + + /** + * Node type constant indicating a node of type + * <code>SimpleType</code>. + * @see SimpleType + */ + public static final int SIMPLE_TYPE = 43; + + /** + * Node type constant indicating a node of type + * <code>SingleVariableDeclaration</code>. + * @see SingleVariableDeclaration + */ + public static final int SINGLE_VARIABLE_DECLARATION = 44; + + /** + * Node type constant indicating a node of type + * <code>StringLiteral</code>. + * @see StringLiteral + */ + public static final int STRING_LITERAL = 45; + + /** + * Node type constant indicating a node of type + * <code>SuperConstructorInvocation</code>. + * @see SuperConstructorInvocation + */ + public static final int SUPER_CONSTRUCTOR_INVOCATION = 46; + + /** + * Node type constant indicating a node of type + * <code>SuperFieldAccess</code>. + * @see SuperFieldAccess + */ + public static final int SUPER_FIELD_ACCESS = 47; + + /** + * Node type constant indicating a node of type + * <code>SuperMethodInvocation</code>. + * @see SuperMethodInvocation + */ + public static final int SUPER_METHOD_INVOCATION = 48; + + /** + * Node type constant indicating a node of type + * <code>SwitchCase</code>. + * @see SwitchCase + */ + public static final int SWITCH_CASE = 49; + + /** + * Node type constant indicating a node of type + * <code>SwitchStatement</code>. + * @see SwitchStatement + */ + public static final int SWITCH_STATEMENT = 50; + + /** + * Node type constant indicating a node of type + * <code>SynchronizedStatement</code>. + * @see SynchronizedStatement + */ + public static final int SYNCHRONIZED_STATEMENT = 51; + + /** + * Node type constant indicating a node of type + * <code>ThisExpression</code>. + * @see ThisExpression + */ + public static final int THIS_EXPRESSION = 52; + + /** + * Node type constant indicating a node of type + * <code>ThrowStatement</code>. + * @see ThrowStatement + */ + public static final int THROW_STATEMENT = 53; + + /** + * Node type constant indicating a node of type + * <code>TryStatement</code>. + * @see TryStatement + */ + public static final int TRY_STATEMENT = 54; + + /** + * Node type constant indicating a node of type + * <code>TypeDeclaration</code>. + * @see TypeDeclaration + */ + public static final int TYPE_DECLARATION = 55; + + /** + * Node type constant indicating a node of type + * <code>TypeDeclarationStatement</code>. + * @see TypeDeclarationStatement + */ + public static final int TYPE_DECLARATION_STATEMENT = 56; + + /** + * Node type constant indicating a node of type + * <code>TypeLiteral</code>. + * @see TypeLiteral + */ + public static final int TYPE_LITERAL = 57; + + /** + * Node type constant indicating a node of type + * <code>VariableDeclarationExpression</code>. + * @see VariableDeclarationExpression + */ + public static final int VARIABLE_DECLARATION_EXPRESSION = 58; + + /** + * Node type constant indicating a node of type + * <code>VariableDeclarationFragment</code>. + * @see VariableDeclarationFragment + */ + public static final int VARIABLE_DECLARATION_FRAGMENT = 59; + + /** + * Node type constant indicating a node of type + * <code>VariableDeclarationStatement</code>. + * @see VariableDeclarationStatement + */ + public static final int VARIABLE_DECLARATION_STATEMENT = 60; + + /** + * Node type constant indicating a node of type + * <code>WhileStatement</code>. + * @see WhileStatement + */ + public static final int WHILE_STATEMENT = 61; + + /** + * Node type constant indicating a node of type + * <code>InstanceofExpression</code>. + * @see InstanceofExpression + */ + public static final int INSTANCEOF_EXPRESSION = 62; + + /** + * Node type constant indicating a node of type + * <code>LineComment</code>. + * @see LineComment + * @since 3.0 + */ + public static final int LINE_COMMENT = 63; + + /** + * Node type constant indicating a node of type + * <code>BlockComment</code>. + * @see BlockComment + * @since 3.0 + */ + public static final int BLOCK_COMMENT = 64; + + /** + * Node type constant indicating a node of type + * <code>TagElement</code>. + * @see TagElement + * @since 3.0 + */ + public static final int TAG_ELEMENT = 65; + + /** + * Node type constant indicating a node of type + * <code>TextElement</code>. + * @see TextElement + * @since 3.0 + */ + public static final int TEXT_ELEMENT = 66; + + /** + * Node type constant indicating a node of type + * <code>MemberRef</code>. + * @see MemberRef + * @since 3.0 + */ + public static final int MEMBER_REF = 67; + + /** + * Node type constant indicating a node of type + * <code>MethodRef</code>. + * @see MethodRef + * @since 3.0 + */ + public static final int METHOD_REF = 68; + + /** + * Node type constant indicating a node of type + * <code>MethodRefParameter</code>. + * @see MethodRefParameter + * @since 3.0 + */ + public static final int METHOD_REF_PARAMETER = 69; + + /** + * Node type constant indicating a node of type + * <code>EnhancedForStatement</code>. + * @see EnhancedForStatement + * @since 3.1 + */ + public static final int ENHANCED_FOR_STATEMENT = 70; + + /** + * Node type constant indicating a node of type + * <code>EnumDeclaration</code>. + * @see EnumDeclaration + * @since 3.1 + */ + public static final int ENUM_DECLARATION = 71; + + /** + * Node type constant indicating a node of type + * <code>EnumConstantDeclaration</code>. + * @see EnumConstantDeclaration + * @since 3.1 + */ + public static final int ENUM_CONSTANT_DECLARATION = 72; + + /** + * Node type constant indicating a node of type + * <code>TypeParameter</code>. + * @see TypeParameter + * @since 3.1 + */ + public static final int TYPE_PARAMETER = 73; + + /** + * Node type constant indicating a node of type + * <code>ParameterizedType</code>. + * @see ParameterizedType + * @since 3.1 + */ + public static final int PARAMETERIZED_TYPE = 74; + + /** + * Node type constant indicating a node of type + * <code>QualifiedType</code>. + * @see QualifiedType + * @since 3.1 + */ + public static final int QUALIFIED_TYPE = 75; + + /** + * Node type constant indicating a node of type + * <code>WildcardType</code>. + * @see WildcardType + * @since 3.1 + */ + public static final int WILDCARD_TYPE = 76; + + /** + * Node type constant indicating a node of type + * <code>NormalAnnotation</code>. + * @see NormalAnnotation + * @since 3.1 + */ + public static final int NORMAL_ANNOTATION = 77; + + /** + * Node type constant indicating a node of type + * <code>MarkerAnnotation</code>. + * @see MarkerAnnotation + * @since 3.1 + */ + public static final int MARKER_ANNOTATION = 78; + + /** + * Node type constant indicating a node of type + * <code>SingleMemberAnnotation</code>. + * @see SingleMemberAnnotation + * @since 3.1 + */ + public static final int SINGLE_MEMBER_ANNOTATION = 79; + + /** + * Node type constant indicating a node of type + * <code>MemberValuePair</code>. + * @see MemberValuePair + * @since 3.1 + */ + public static final int MEMBER_VALUE_PAIR = 80; + + /** + * Node type constant indicating a node of type + * <code>AnnotationTypeDeclaration</code>. + * @see AnnotationTypeDeclaration + * @since 3.1 + */ + public static final int ANNOTATION_TYPE_DECLARATION = 81; + + /** + * Node type constant indicating a node of type + * <code>AnnotationTypeMemberDeclaration</code>. + * @see AnnotationTypeMemberDeclaration + * @since 3.1 + */ + public static final int ANNOTATION_TYPE_MEMBER_DECLARATION = 82; + + /** + * Node type constant indicating a node of type + * <code>Modifier</code>. + * @see Modifier + * @since 3.1 + */ + public static final int MODIFIER = 83; + +//{ObjectTeams: required OT specific node type constants added + + /** + * Node type constant indicating a node of type + * <code>MethodSpec</code>. + * @see MethodSpec + */ + public static final int METHOD_SPEC = 84; + + /** + * Node type constant indicating a node of type + * <code>CallinMappingDeclaration</code>. + * @see CallinMappingDeclaration + */ + public static final int CALLIN_MAPPING_DECLARATION = 85; + + /** + * Node type constant indicating a node of type + * <code>CalloutMappingDeclaration</code>. + * @see CalloutMappingDeclaration + */ + public static final int CALLOUT_MAPPING_DECLARATION = 86; + + /** + * Node type constant indicating a node of type + * <code>LiftingType</code>. + * @see LiftingType + */ + public static final int LIFTING_TYPE = 87; + + /** + * Node type constant indicating a node of type + * <code>WithinStatement</code>. + * @see WithinStatement + */ + public static final int WITHIN_STATEMENT = 88; + + /** + * Node type constant indicating a node of type + * <code>BaseConstructorMessageSend</code>. + * @see BaseConstructorMessageSend + */ + public static final int BASE_CONSTRUCTOR_INVOCATION = 89; + + /** + * Node type constant indicating a node of type + * <code>ParameterMapping</code>. + * @see ParameterMapping + */ + public static final int PARAMETER_MAPPING = 90; + + /** + * Node type constant indicating a node of type + * <code>BaseCallMessageSend</code>. + * @see BaseCallMessageSend + */ + public static final int BASE_CALL_MESSAGE_SEND = 91; + + /** + * Node type constant indicating a node of type + * <code>FieldAccessSpec</code>. + * @see FieldAccessSpec + */ + public static final int FIELD_ACCESS_SPEC = 92; + + /** + * Node type constant indicating a node of type + * <code>RoleTypeDelaration</code>. + * @see RoleTypeDelaration + */ + public static final int ROLE_TYPE_DECLARATION = 93; + + /** + * Node type constant indicating a node of type + * <code>TSuperCallMessageSend</code>. + * @see TSuperCallMessageSend + */ + public static final int TSUPER_MESSAGE_SEND = 94; + + /** + * Node type constant indicating a node of type + * <code>TSuperCallMessageSend</code>. + * @see TSuperCallMessageSend + */ + public static final int TSUPER_CONSTRUCTOR_INVOCATION = 95; + + public static final int TYPE_ANCHOR = 96; + + public static final int PRECEDENCE_DECLARATION = 97; + + public static final int GUARD_PREDICATE_DECLARATION = 98; + + /** @since 1.3.1 */ + public static final int METHOD_BINDING_OPERATOR = 99; +//gbr} + + /** + * Returns the node class for the corresponding node type. + * + * @param nodeType AST node type + * @return the corresponding <code>ASTNode</code> subclass + * @exception IllegalArgumentException if <code>nodeType</code> is + * not a legal AST node type + * @see #getNodeType() + * @since 3.0 + */ + public static Class nodeClassForType(int nodeType) { + switch (nodeType) { + case ANNOTATION_TYPE_DECLARATION : + return AnnotationTypeDeclaration.class; + case ANNOTATION_TYPE_MEMBER_DECLARATION : + return AnnotationTypeMemberDeclaration.class; + case ANONYMOUS_CLASS_DECLARATION : + return AnonymousClassDeclaration.class; + case ARRAY_ACCESS : + return ArrayAccess.class; + case ARRAY_CREATION : + return ArrayCreation.class; + case ARRAY_INITIALIZER : + return ArrayInitializer.class; + case ARRAY_TYPE : + return ArrayType.class; + case ASSERT_STATEMENT : + return AssertStatement.class; + case ASSIGNMENT : + return Assignment.class; + case BLOCK : + return Block.class; + case BLOCK_COMMENT : + return BlockComment.class; + case BOOLEAN_LITERAL : + return BooleanLiteral.class; + case BREAK_STATEMENT : + return BreakStatement.class; + case CAST_EXPRESSION : + return CastExpression.class; + case CATCH_CLAUSE : + return CatchClause.class; + case CHARACTER_LITERAL : + return CharacterLiteral.class; + case CLASS_INSTANCE_CREATION : + return ClassInstanceCreation.class; + case COMPILATION_UNIT : + return CompilationUnit.class; + case CONDITIONAL_EXPRESSION : + return ConditionalExpression.class; + case CONSTRUCTOR_INVOCATION : + return ConstructorInvocation.class; + case CONTINUE_STATEMENT : + return ContinueStatement.class; + case DO_STATEMENT : + return DoStatement.class; + case EMPTY_STATEMENT : + return EmptyStatement.class; + case ENHANCED_FOR_STATEMENT : + return EnhancedForStatement.class; + case ENUM_CONSTANT_DECLARATION : + return EnumConstantDeclaration.class; + case ENUM_DECLARATION : + return EnumDeclaration.class; + case EXPRESSION_STATEMENT : + return ExpressionStatement.class; + case FIELD_ACCESS : + return FieldAccess.class; + case FIELD_DECLARATION : + return FieldDeclaration.class; + case FOR_STATEMENT : + return ForStatement.class; + case IF_STATEMENT : + return IfStatement.class; + case IMPORT_DECLARATION : + return ImportDeclaration.class; + case INFIX_EXPRESSION : + return InfixExpression.class; + case INITIALIZER : + return Initializer.class; + case INSTANCEOF_EXPRESSION : + return InstanceofExpression.class; + case JAVADOC : + return Javadoc.class; + case LABELED_STATEMENT : + return LabeledStatement.class; + case LINE_COMMENT : + return LineComment.class; + case MARKER_ANNOTATION : + return MarkerAnnotation.class; + case MEMBER_REF : + return MemberRef.class; + case MEMBER_VALUE_PAIR : + return MemberValuePair.class; + case METHOD_DECLARATION : + return MethodDeclaration.class; + case METHOD_INVOCATION : + return MethodInvocation.class; + case METHOD_REF : + return MethodRef.class; + case METHOD_REF_PARAMETER : + return MethodRefParameter.class; + case MODIFIER : + return Modifier.class; + case NORMAL_ANNOTATION : + return NormalAnnotation.class; + case NULL_LITERAL : + return NullLiteral.class; + case NUMBER_LITERAL : + return NumberLiteral.class; + case PACKAGE_DECLARATION : + return PackageDeclaration.class; + case PARAMETERIZED_TYPE : + return ParameterizedType.class; + case PARENTHESIZED_EXPRESSION : + return ParenthesizedExpression.class; + case POSTFIX_EXPRESSION : + return PostfixExpression.class; + case PREFIX_EXPRESSION : + return PrefixExpression.class; + case PRIMITIVE_TYPE : + return PrimitiveType.class; + case QUALIFIED_NAME : + return QualifiedName.class; + case QUALIFIED_TYPE : + return QualifiedType.class; + case RETURN_STATEMENT : + return ReturnStatement.class; + case SIMPLE_NAME : + return SimpleName.class; + case SIMPLE_TYPE : + return SimpleType.class; + case SINGLE_MEMBER_ANNOTATION : + return SingleMemberAnnotation.class; + case SINGLE_VARIABLE_DECLARATION : + return SingleVariableDeclaration.class; + case STRING_LITERAL : + return StringLiteral.class; + case SUPER_CONSTRUCTOR_INVOCATION : + return SuperConstructorInvocation.class; + case SUPER_FIELD_ACCESS : + return SuperFieldAccess.class; + case SUPER_METHOD_INVOCATION : + return SuperMethodInvocation.class; + case SWITCH_CASE: + return SwitchCase.class; + case SWITCH_STATEMENT : + return SwitchStatement.class; + case SYNCHRONIZED_STATEMENT : + return SynchronizedStatement.class; + case TAG_ELEMENT : + return TagElement.class; + case TEXT_ELEMENT : + return TextElement.class; + case THIS_EXPRESSION : + return ThisExpression.class; + case THROW_STATEMENT : + return ThrowStatement.class; + case TRY_STATEMENT : + return TryStatement.class; + case TYPE_DECLARATION : + return TypeDeclaration.class; + case TYPE_DECLARATION_STATEMENT : + return TypeDeclarationStatement.class; + case TYPE_LITERAL : + return TypeLiteral.class; + case TYPE_PARAMETER : + return TypeParameter.class; + case VARIABLE_DECLARATION_EXPRESSION : + return VariableDeclarationExpression.class; + case VARIABLE_DECLARATION_FRAGMENT : + return VariableDeclarationFragment.class; + case VARIABLE_DECLARATION_STATEMENT : + return VariableDeclarationStatement.class; + case WHILE_STATEMENT : + return WhileStatement.class; + case WILDCARD_TYPE : + return WildcardType.class; +//{ObjectTeams: entries for OT specific node types added + case METHOD_SPEC : + return MethodSpec.class; + case CALLIN_MAPPING_DECLARATION : + return CallinMappingDeclaration.class; + case CALLOUT_MAPPING_DECLARATION : + return CalloutMappingDeclaration.class; + case LIFTING_TYPE : + return LiftingType.class; + case WITHIN_STATEMENT : + return WithinStatement.class; + case TSUPER_MESSAGE_SEND : + return TSuperMessageSend.class; + case TSUPER_CONSTRUCTOR_INVOCATION : + return TSuperConstructorInvocation.class; + case BASE_CONSTRUCTOR_INVOCATION : + return BaseConstructorInvocation.class; + case PARAMETER_MAPPING : + return ParameterMapping.class; + case BASE_CALL_MESSAGE_SEND : + return BaseCallMessageSend.class; + case FIELD_ACCESS_SPEC : + return FieldAccessSpec.class; + case ROLE_TYPE_DECLARATION : + return RoleTypeDeclaration.class; + case TYPE_ANCHOR : + return TypeAnchor.class; + case PRECEDENCE_DECLARATION : + return PrecedenceDeclaration.class; + case GUARD_PREDICATE_DECLARATION : + return GuardPredicateDeclaration.class; + case METHOD_BINDING_OPERATOR : + return MethodBindingOperator.class; +//gbr} + } + throw new IllegalArgumentException(); + } + + /** + * Owning AST. + * <p> + * N.B. This ia a private field, but declared as package-visible + * for more efficient access from inner classes. + * </p> + */ + final AST ast; + + /** + * Parent AST node, or <code>null</code> if this node is a root. + * Initially <code>null</code>. + */ + private ASTNode parent = null; + + /** + * An unmodifiable empty map (used to implement <code>properties()</code>). + */ + private static final Map UNMODIFIABLE_EMPTY_MAP + = Collections.unmodifiableMap(new HashMap(1)); + + /** + * Primary field used in representing node properties efficiently. + * If <code>null</code>, this node has no properties. + * If a <code>String</code>, this is the name of this node's sole property, + * and <code>property2</code> contains its value. + * If a <code>HashMap</code>, this is the table of property name-value + * mappings; <code>property2</code>, if non-null is its unmodifiable + * equivalent. + * Initially <code>null</code>. + * + * @see #property2 + */ + private Object property1 = null; + + /** + * Auxillary field used in representing node properties efficiently. + * + * @see #property1 + */ + private Object property2 = null; + + /** + * A character index into the original source string, + * or <code>-1</code> if no source position information is available + * for this node; <code>-1</code> by default. + */ + private int startPosition = -1; + + /** + * A character length, or <code>0</code> if no source position + * information is recorded for this node; <code>0</code> by default. + */ + private int length = 0; + + /** + * Flag constant (bit mask, value 1) indicating that there is something + * not quite right with this AST node. + * <p> + * The standard parser (<code>ASTParser</code>) sets this + * flag on a node to indicate a syntax error detected in the vicinity. + * </p> + */ + public static final int MALFORMED = 1; + + /** + * Flag constant (bit mask, value 2) indicating that this is a node + * that was created by the parser (as opposed to one created by another + * party). + * <p> + * The standard parser (<code>ASTParser</code>) sets this + * flag on the nodes it creates. + * </p> + * @since 3.0 + */ + public static final int ORIGINAL = 2; + + /** + * Flag constant (bit mask, value 4) indicating that this node + * is unmodifiable. When a node is marked unmodifiable, the + * following operations result in a runtime exception: + * <ul> + * <li>Change a simple property of this node.</li> + * <li>Add or remove a child node from this node.</li> + * <li>Parent (or reparent) this node.</li> + * </ul> + * <p> + * The standard parser (<code>ASTParser</code>) does not set + * this flag on the nodes it creates. However, clients may set + * this flag on a node to prevent further modification of the + * its structural properties. + * </p> + * @since 3.0 + */ + public static final int PROTECT = 4; + + /** + * Flag constant (bit mask, value 8) indicating that this node + * or a part of this node is recovered from source that contains + * a syntax error detected in the vicinity. + * <p> + * The standard parser (<code>ASTParser</code>) sets this + * flag on a node to indicate a recovered node. + * </p> + * @since 3.2 + */ + public static final int RECOVERED = 8; + + /** + * int containing the node type in the top 16 bits and + * flags in the bottom 16 bits; none set by default. + * <p> + * N.B. This is a private field, but declared as package-visible + * for more efficient access from inner classes. + * </p> + * + * @see #MALFORMED + */ + int typeAndFlags = 0; + + /** + * Property of parent in which this node is a child, or <code>null</code> + * if this node is a root. Initially <code>null</code>. + * + * @see #getLocationInParent + * @since 3.0 + */ + private StructuralPropertyDescriptor location = null; + + /** Internal convenience constant indicating that there is definite risk of cycles. + * @since 3.0 + */ + static final boolean CYCLE_RISK = true; + + /** Internal convenience constant indicating that there is no risk of cycles. + * @since 3.0 + */ + static final boolean NO_CYCLE_RISK = false; + + /** Internal convenience constant indicating that a structural property is mandatory. + * @since 3.0 + */ + static final boolean MANDATORY = true; + + /** Internal convenience constant indicating that a structural property is optional. + * @since 3.0 + */ + static final boolean OPTIONAL = false; + + /** + * A specialized implementation of a list of ASTNodes. The + * implementation is based on an ArrayList. + */ + class NodeList extends AbstractList { + + /** + * The underlying list in which the nodes of this list are + * stored (element type: <code>ASTNode</code>). + * <p> + * Be stingy on storage - assume that list will be empty. + * </p> + * <p> + * This field declared default visibility (rather than private) + * so that accesses from <code>NodeList.Cursor</code> do not require + * a synthetic accessor method. + * </p> + */ + ArrayList store = new ArrayList(0); + + /** + * The property descriptor for this list. + */ + ChildListPropertyDescriptor propertyDescriptor; + + /** + * A cursor for iterating over the elements of the list. + * Does not lose its position if the list is changed during + * the iteration. + */ + class Cursor implements Iterator { + /** + * The position of the cursor between elements. If the value + * is N, then the cursor sits between the element at positions + * N-1 and N. Initially just before the first element of the + * list. + */ + private int position = 0; + + /* (non-Javadoc) + * Method declared on <code>Iterator</code>. + */ + public boolean hasNext() { + return this.position < NodeList.this.store.size(); + } + + /* (non-Javadoc) + * Method declared on <code>Iterator</code>. + */ + public Object next() { + Object result = NodeList.this.store.get(this.position); + this.position++; + return result; + } + + /* (non-Javadoc) + * Method declared on <code>Iterator</code>. + */ + public void remove() { + throw new UnsupportedOperationException(); + } + + /** + * Adjusts this cursor to accomodate an add/remove at the given + * index. + * + * @param index the position at which the element was added + * or removed + * @param delta +1 for add, and -1 for remove + */ + void update(int index, int delta) { + if (this.position > index) { + // the cursor has passed the added or removed element + this.position += delta; + } + } + } + + /** + * A list of currently active cursors (element type: + * <code>Cursor</code>), or <code>null</code> if there are no + * active cursors. + * <p> + * It is important for storage considerations to maintain the + * null-means-empty invariant; otherwise, every NodeList instance + * will waste a lot of space. A cursor is needed only for the duration + * of a visit to the child nodes. Under normal circumstances, only a + * single cursor is needed; multiple cursors are only required if there + * are multiple visits going on at the same time. + * </p> + */ + private List cursors = null; + + /** + * Creates a new empty list of nodes owned by this node. + * This node will be the common parent of all nodes added to + * this list. + * + * @param property the property descriptor + * @since 3.0 + */ + NodeList(ChildListPropertyDescriptor property) { + super(); + this.propertyDescriptor = property; + } + + /* (non-javadoc) + * @see java.util.AbstractCollection#size() + */ + public int size() { + return this.store.size(); + } + + /* (non-javadoc) + * @see AbstractList#get(int) + */ + public Object get(int index) { + return this.store.get(index); + } + + /* (non-javadoc) + * @see List#set(int, java.lang.Object) + */ + public Object set(int index, Object element) { + if (element == null) { + throw new IllegalArgumentException(); + } + if ((ASTNode.this.typeAndFlags & PROTECT) != 0) { + // this node is protected => cannot gain or lose children + throw new IllegalArgumentException("AST node cannot be modified"); //$NON-NLS-1$ + } + // delink old child from parent, and link new child to parent + ASTNode newChild = (ASTNode) element; + ASTNode oldChild = (ASTNode) this.store.get(index); + if (oldChild == newChild) { + return oldChild; + } + if ((oldChild.typeAndFlags & PROTECT) != 0) { + // old child is protected => cannot be unparented + throw new IllegalArgumentException("AST node cannot be modified"); //$NON-NLS-1$ + } + ASTNode.checkNewChild(ASTNode.this, newChild, this.propertyDescriptor.cycleRisk, this.propertyDescriptor.elementType); + ASTNode.this.ast.preReplaceChildEvent(ASTNode.this, oldChild, newChild, this.propertyDescriptor); + + Object result = this.store.set(index, newChild); + // n.b. setParent will call ast.modifying() + oldChild.setParent(null, null); + newChild.setParent(ASTNode.this, this.propertyDescriptor); + ASTNode.this.ast.postReplaceChildEvent(ASTNode.this, oldChild, newChild, this.propertyDescriptor); + return result; + } + + /* (non-javadoc) + * @see List#add(int, java.lang.Object) + */ + public void add(int index, Object element) { + if (element == null) { + throw new IllegalArgumentException(); + } + if ((ASTNode.this.typeAndFlags & PROTECT) != 0) { + // this node is protected => cannot gain or lose children + throw new IllegalArgumentException("AST node cannot be modified"); //$NON-NLS-1$ + } + // link new child to parent + ASTNode newChild = (ASTNode) element; + ASTNode.checkNewChild(ASTNode.this, newChild, this.propertyDescriptor.cycleRisk, this.propertyDescriptor.elementType); + ASTNode.this.ast.preAddChildEvent(ASTNode.this, newChild, this.propertyDescriptor); + + + this.store.add(index, element); + updateCursors(index, +1); + // n.b. setParent will call ast.modifying() + newChild.setParent(ASTNode.this, this.propertyDescriptor); + ASTNode.this.ast.postAddChildEvent(ASTNode.this, newChild, this.propertyDescriptor); + } + + /* (non-javadoc) + * @see List#remove(int) + */ + public Object remove(int index) { + if ((ASTNode.this.typeAndFlags & PROTECT) != 0) { + // this node is protected => cannot gain or lose children + throw new IllegalArgumentException("AST node cannot be modified"); //$NON-NLS-1$ + } + // delink old child from parent + ASTNode oldChild = (ASTNode) this.store.get(index); + if ((oldChild.typeAndFlags & PROTECT) != 0) { + // old child is protected => cannot be unparented + throw new IllegalArgumentException("AST node cannot be modified"); //$NON-NLS-1$ + } + + ASTNode.this.ast.preRemoveChildEvent(ASTNode.this, oldChild, this.propertyDescriptor); + // n.b. setParent will call ast.modifying() + oldChild.setParent(null, null); + Object result = this.store.remove(index); + updateCursors(index, -1); + ASTNode.this.ast.postRemoveChildEvent(ASTNode.this, oldChild, this.propertyDescriptor); + return result; + + } + + /** + * Allocate a cursor to use for a visit. The client must call + * <code>releaseCursor</code> when done. + * <p> + * This method is internally synchronized on this NodeList. + * It is thread-safe to create a cursor. + * </p> + * + * @return a new cursor positioned before the first element + * of the list + */ + Cursor newCursor() { + synchronized (this) { + // serialize cursor management on this NodeList + if (this.cursors == null) { + // convert null to empty list + this.cursors = new ArrayList(1); + } + Cursor result = new Cursor(); + this.cursors.add(result); + return result; + } + } + + /** + * Releases the given cursor at the end of a visit. + * <p> + * This method is internally synchronized on this NodeList. + * It is thread-safe to release a cursor. + * </p> + * + * @param cursor the cursor + */ + void releaseCursor(Cursor cursor) { + synchronized (this) { + // serialize cursor management on this NodeList + this.cursors.remove(cursor); + if (this.cursors.isEmpty()) { + // important: convert empty list back to null + // otherwise the node will hang on to needless junk + this.cursors = null; + } + } + } + + /** + * Adjusts all cursors to accomodate an add/remove at the given + * index. + * <p> + * This method is only used when the list is being modified. + * The AST is not thread-safe if any of the clients are modifying it. + * </p> + * + * @param index the position at which the element was added + * or removed + * @param delta +1 for add, and -1 for remove + */ + private synchronized void updateCursors(int index, int delta) { + if (this.cursors == null) { + // there are no cursors to worry about + return; + } + for (Iterator it = this.cursors.iterator(); it.hasNext(); ) { + Cursor c = (Cursor) it.next(); + c.update(index, delta); + } + } + + /** + * Returns an estimate of the memory footprint of this node list + * instance in bytes. + * <ul> + * <li>1 object header for the NodeList instance</li> + * <li>5 4-byte fields of the NodeList instance</li> + * <li>0 for cursors since null unless walk in progress</li> + * <li>1 object header for the ArrayList instance</li> + * <li>2 4-byte fields of the ArrayList instance</li> + * <li>1 object header for an Object[] instance</li> + * <li>4 bytes in array for each element</li> + * </ul> + * + * @return the size of this node list in bytes + */ + int memSize() { + int result = HEADERS + 5 * 4; + result += HEADERS + 2 * 4; + result += HEADERS + 4 * size(); + return result; + } + + /** + * Returns an estimate of the memory footprint in bytes of this node + * list and all its subtrees. + * + * @return the size of this list of subtrees in bytes + */ + int listSize() { + int result = memSize(); + for (Iterator it = iterator(); it.hasNext(); ) { + ASTNode child = (ASTNode) it.next(); + result += child.treeSize(); + } + return result; + } + } + + /** + * Creates a new AST node owned by the given AST. Once established, + * the relationship between an AST node and its owning AST does not change + * over the lifetime of the node. The new node has no parent node, + * and no properties. + * <p> + * N.B. This constructor is package-private; all subclasses my be + * declared in the same package; clients are unable to declare + * additional subclasses. + * </p> + * + * @param ast the AST that is to own this node + */ + ASTNode(AST ast) { + if (ast == null) { + throw new IllegalArgumentException(); + } + + this.ast = ast; + setNodeType(getNodeType0()); + setFlags(ast.getDefaultNodeFlag()); + // setFlags calls modifying(); + } + + /** + * Returns this node's AST. + * <p> + * Note that the relationship between an AST node and its owing AST does + * not change over the lifetime of a node. + * </p> + * + * @return the AST that owns this node + */ + public final AST getAST() { + return this.ast; + } + + /** + * Returns this node's parent node, or <code>null</code> if this is the + * root node. + * <p> + * Note that the relationship between an AST node and its parent node + * may change over the lifetime of a node. + * </p> + * + * @return the parent of this node, or <code>null</code> if none + */ + public final ASTNode getParent() { + return this.parent; + } + + /** + * Returns the location of this node within its parent, + * or <code>null</code> if this is a root node. + * <p> + * <pre> + * ASTNode node = ...; + * ASTNode parent = node.getParent(); + * StructuralPropertyDescriptor location = node.getLocationInParent(); + * assert (parent != null) == (location != null); + * if ((location != null) && location.isChildProperty()) + * assert parent.getStructuralProperty(location) == node; + * if ((location != null) && location.isChildListProperty()) + * assert ((List) parent.getStructuralProperty(location)).contains(node); + * </pre> + * </p> + * <p> + * Note that the relationship between an AST node and its parent node + * may change over the lifetime of a node. + * </p> + * + * @return the location of this node in its parent, + * or <code>null</code> if this node has no parent + * @since 3.0 + */ + public final StructuralPropertyDescriptor getLocationInParent() { + return this.location; + } + + /** + * Returns the root node at or above this node; returns this node if + * it is a root. + * + * @return the root node at or above this node + */ + public final ASTNode getRoot() { + ASTNode candidate = this; + while (true) { + ASTNode p = candidate.getParent(); + if (p == null) { + // candidate has no parent - that's the guy + return candidate; + } + candidate = p; + } + } + + /** + * Returns the value of the given structural property for this node. The value + * returned depends on the kind of property: + * <ul> + * <li>{@link SimplePropertyDescriptor} - the value of the given simple property, + * or <code>null</code> if none; primitive values are "boxed"</li> + * <li>{@link ChildPropertyDescriptor} - the child node (type <code>ASTNode</code>), + * or <code>null</code> if none</li> + * <li>{@link ChildListPropertyDescriptor} - the list (element type: {@link ASTNode})</li> + * </ul> + * + * @param property the property + * @return the value, or <code>null</code> if none + * @exception RuntimeException if this node does not have the given property + * @since 3.0 + */ + public final Object getStructuralProperty(StructuralPropertyDescriptor property) { + if (property instanceof SimplePropertyDescriptor) { + SimplePropertyDescriptor p = (SimplePropertyDescriptor) property; + if (p.getValueType() == int.class) { + int result = internalGetSetIntProperty(p, true, 0); + return new Integer(result); + } else if (p.getValueType() == boolean.class) { + boolean result = internalGetSetBooleanProperty(p, true, false); + return Boolean.valueOf(result); + } else { + return internalGetSetObjectProperty(p, true, null); + } + } + if (property instanceof ChildPropertyDescriptor) { + return internalGetSetChildProperty((ChildPropertyDescriptor) property, true, null); + } + if (property instanceof ChildListPropertyDescriptor) { + return internalGetChildListProperty((ChildListPropertyDescriptor) property); + } + throw new IllegalArgumentException(); + } + + /** + * Sets the value of the given structural property for this node. The value + * passed depends on the kind of property: + * <ul> + * <li>{@link SimplePropertyDescriptor} - the new value of the given simple property, + * or <code>null</code> if none; primitive values are "boxed"</li> + * <li>{@link ChildPropertyDescriptor} - the new child node (type <code>ASTNode</code>), + * or <code>null</code> if none</li> + * <li>{@link ChildListPropertyDescriptor} - not allowed</li> + * </ul> + * + * @param property the property + * @param value the property value + * @exception RuntimeException if this node does not have the + * given property, or if the given property cannot be set + * @since 3.0 + */ + public final void setStructuralProperty(StructuralPropertyDescriptor property, Object value) { + if (property instanceof SimplePropertyDescriptor) { + SimplePropertyDescriptor p = (SimplePropertyDescriptor) property; + if (p.getValueType() == int.class) { + int arg = ((Integer) value).intValue(); + internalGetSetIntProperty(p, false, arg); + return; + } else if (p.getValueType() == boolean.class) { + boolean arg = ((Boolean) value).booleanValue(); + internalGetSetBooleanProperty(p, false, arg); + return; + } else { + if (value == null && p.isMandatory()) { + throw new IllegalArgumentException(); + } + internalGetSetObjectProperty(p, false, value); + return; + } + } + if (property instanceof ChildPropertyDescriptor) { + ChildPropertyDescriptor p = (ChildPropertyDescriptor) property; + ASTNode child = (ASTNode) value; + if (child == null && p.isMandatory()) { + throw new IllegalArgumentException(); + } + internalGetSetChildProperty(p, false, child); + return; + } + if (property instanceof ChildListPropertyDescriptor) { + throw new IllegalArgumentException("Cannot set the list of child list property"); //$NON-NLS-1$ + } + } + + /** + * Sets the value of the given int-valued property for this node. + * The default implementation of this method throws an exception explaining + * that this node does not have such a property. This method should be + * extended in subclasses that have at leasy one simple property whose value + * type is int. + * + * @param property the property + * @param get <code>true</code> for a get operation, and + * <code>false</code> for a set operation + * @param value the new property value; ignored for get operations + * @return the value; always returns + * <code>0</code> for set operations + * @exception RuntimeException if this node does not have the + * given property, or if the given value cannot be set as specified + * @since 3.0 + */ + int internalGetSetIntProperty(SimplePropertyDescriptor property, boolean get, int value) { + throw new RuntimeException("Node does not have this property"); //$NON-NLS-1$ + } + + /** + * Sets the value of the given boolean-valued property for this node. + * The default implementation of this method throws an exception explaining + * that this node does not have such a property. This method should be + * extended in subclasses that have at leasy one simple property whose value + * type is boolean. + * + * @param property the property + * @param get <code>true</code> for a get operation, and + * <code>false</code> for a set operation + * @param value the new property value; ignored for get operations + * @return the value; always returns + * <code>false</code> for set operations + * @exception RuntimeException if this node does not have the + * given property, or if the given value cannot be set as specified + * @since 3.0 + */ + boolean internalGetSetBooleanProperty(SimplePropertyDescriptor property, boolean get, boolean value) { + throw new RuntimeException("Node does not have this property"); //$NON-NLS-1$ + } + + /** + * Sets the value of the given property for this node. + * The default implementation of this method throws an exception explaining + * that this node does not have such a property. This method should be + * extended in subclasses that have at leasy one simple property whose value + * type is a reference type. + * + * @param property the property + * @param get <code>true</code> for a get operation, and + * <code>false</code> for a set operation + * @param value the new property value, or <code>null</code> if none; + * ignored for get operations + * @return the value, or <code>null</code> if none; always returns + * <code>null</code> for set operations + * @exception RuntimeException if this node does not have the + * given property, or if the given value cannot be set as specified + * @since 3.0 + */ + Object internalGetSetObjectProperty(SimplePropertyDescriptor property, boolean get, Object value) { + throw new RuntimeException("Node does not have this property"); //$NON-NLS-1$ + } + + /** + * Sets the child value of the given property for this node. + * The default implementation of this method throws an exception explaining + * that this node does not have such a property. This method should be + * extended in subclasses that have at leasy one child property. + * + * @param property the property + * @param get <code>true</code> for a get operation, and + * <code>false</code> for a set operation + * @param child the new child value, or <code>null</code> if none; + * always <code>null</code> for get operations + * @return the child, or <code>null</code> if none; always returns + * <code>null</code> for set operations + * @exception RuntimeException if this node does not have the + * given property, or if the given child cannot be set as specified + * @since 3.0 + */ + ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + throw new RuntimeException("Node does not have this property"); //$NON-NLS-1$ + } + + /** + * Returns the list value of the given property for this node. + * The default implementation of this method throws an exception explaining + * that this noed does not have such a property. This method should be + * extended in subclasses that have at leasy one child list property. + * + * @param property the property + * @return the list (element type: {@link ASTNode}) + * @exception RuntimeException if the given node does not have the + * given property + * @since 3.0 + */ + List internalGetChildListProperty(ChildListPropertyDescriptor property) { + throw new RuntimeException("Node does not have this property"); //$NON-NLS-1$ + } + + /** + * Returns a list of structural property descriptors for nodes of the + * same type as this node. Clients must not modify the result. + * <p> + * Note that property descriptors are a meta-level mechanism + * for manipulating ASTNodes in a generic way. They are + * unrelated to <code>get/setProperty</code>. + * </p> + * + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public final List structuralPropertiesForType() { + return internalStructuralPropertiesForType(this.ast.apiLevel); + } + + /** + * Returns a list of property descriptors for this node type. + * Clients must not modify the result. This abstract method + * must be implemented in each concrete AST node type. + * <p> + * N.B. This method is package-private, so that the implementations + * of this method in each of the concrete AST node types do not + * clutter up the API doc. + * </p> + * + * @param apiLevel the API level; one of the <code>AST.JLS*</code> constants + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + abstract List internalStructuralPropertiesForType(int apiLevel); + + /** + * Internal helper method that starts the building a list of + * property descriptors for the given node type. + * + * @param nodeClass the class for a concrete node type + * @param propertyList empty list + */ + static void createPropertyList(Class nodeClass, List propertyList) { + // stuff nodeClass at head of list for future ref + propertyList.add(nodeClass); + } + + /** + * Internal helper method that adding a property descriptor. + * + * @param property the structural property descriptor + * @param propertyList list beginning with the AST node class + * followed by accumulated structural property descriptors + */ + static void addProperty(StructuralPropertyDescriptor property, List propertyList) { + Class nodeClass = (Class) propertyList.get(0); + if (property.getNodeClass() != nodeClass) { + // easily made cut-and-paste mistake + throw new RuntimeException("Structural property descriptor has wrong node class!"); //$NON-NLS-1$ + } + propertyList.add(property); + } + + /** + * Internal helper method that completes the building of + * a node type's structural property descriptor list. + * + * @param propertyList list beginning with the AST node class + * followed by accumulated structural property descriptors + * @return unmodifiable list of structural property descriptors + * (element type: <code>StructuralPropertyDescriptor</code>) + */ + static List reapPropertyList(List propertyList) { + propertyList.remove(0); // remove nodeClass + // compact + ArrayList a = new ArrayList(propertyList.size()); + a.addAll(propertyList); + return Collections.unmodifiableList(a); + } + + /** + * Checks that this AST operation is not used when + * building JLS2 level ASTs. + + * @exception UnsupportedOperationException + * @since 3.0 + */ + final void unsupportedIn2() { + if (this.ast.apiLevel == AST.JLS2_INTERNAL) { + throw new UnsupportedOperationException("Operation not supported in JLS2 AST"); //$NON-NLS-1$ + } + } + + /** + * Checks that this AST operation is only used when + * building JLS2 level ASTs. + + * @exception UnsupportedOperationException + * @since 3.0 + */ + final void supportedOnlyIn2() { + if (this.ast.apiLevel != AST.JLS2_INTERNAL) { + throw new UnsupportedOperationException("Operation only supported in JLS2 AST"); //$NON-NLS-1$ + } + } + + /** + * Sets or clears this node's parent node and location. + * <p> + * Note that this method is package-private. The pointer from a node + * to its parent is set implicitly as a side effect of inserting or + * removing the node as a child of another node. This method calls + * <code>ast.modifying()</code>. + * </p> + * + * @param parent the new parent of this node, or <code>null</code> if none + * @param property the location of this node in its parent, + * or <code>null</code> if <code>parent</code> is <code>null</code> + * @see #getLocationInParent + * @see #getParent + * @since 3.0 + */ + final void setParent(ASTNode parent, StructuralPropertyDescriptor property) { + this.ast.modifying(); + this.parent = parent; + this.location = property; + } + + /** + * Removes this node from its parent. Has no effect if this node + * is unparented. If this node appears as an element of a child list + * property of its parent, then this node is removed from the + * list using <code>List.remove</code>. + * If this node appears as the value of a child property of its + * parent, then this node is detached from its parent + * by passing <code>null</code> to the appropriate setter method; + * this operation fails if this node is in a mandatory property. + * + * @since 3.0 + */ + public final void delete() { + StructuralPropertyDescriptor p = getLocationInParent(); + if (p == null) { + // node is unparented + return; + } + if (p.isChildProperty()) { + getParent().setStructuralProperty(this.location, null); + return; + } + if (p.isChildListProperty()) { + List l = (List) getParent().getStructuralProperty(this.location); + l.remove(this); + } + } + + /** + * Checks whether the given new child node is a node + * in a different AST from its parent-to-be, whether it is + * already has a parent, whether adding it to its + * parent-to-be would create a cycle, and whether the child is of + * the right type. The parent-to-be is the enclosing instance. + * + * @param node the parent-to-be node + * @param newChild the new child of the parent + * @param cycleCheck <code>true</code> if cycles are possible and need + * to be checked, <code>false</code> if cycles are impossible and do + * not need to be checked + * @param nodeType a type constraint on child nodes, or <code>null</code> + * if no special check is required + * @exception IllegalArgumentException if: + * <ul> + * <li>the child is null</li> + * <li>the node belongs to a different AST</li> + * <li>the child has the incorrect node type</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + static void checkNewChild(ASTNode node, ASTNode newChild, + boolean cycleCheck, Class nodeType) { + if (newChild.ast != node.ast) { + // new child is from a different AST + throw new IllegalArgumentException(); + } + if (newChild.getParent() != null) { + // new child currently has a different parent + throw new IllegalArgumentException(); + } + if (cycleCheck && newChild == node.getRoot()) { + // inserting new child would create a cycle + throw new IllegalArgumentException(); + } + Class childClass = newChild.getClass(); + if (nodeType != null && !nodeType.isAssignableFrom(childClass)) { + // new child is not of the right type + throw new ClassCastException(); + } + if ((newChild.typeAndFlags & PROTECT) != 0) { + // new child node is protected => cannot be parented + throw new IllegalArgumentException("AST node cannot be modified"); //$NON-NLS-1$ + } + } + + /** + * Prelude portion of the "3 step program" for replacing the + * old child of this node with another node. + * Here is the code pattern found in all AST node subclasses: + * <pre> + * ASTNode oldChild = this.foo; + * preReplaceChild(oldChild, newFoo, FOO_PROPERTY); + * this.foo = newFoo; + * postReplaceChild(oldChild, newFoo, FOO_PROPERTY); + * </pre> + * The first part (preReplaceChild) does all the precondition checks, + * reports pre-delete events, and changes parent links. + * The old child is delinked from its parent (making it a root node), + * and the new child node is linked to its parent. The new child node + * must be a root node in the same AST as its new parent, and must not + * be an ancestor of this node. All three nodes must be + * modifiable (not PROTECTED). The replace operation must fail + * atomically; so it is crucial that all precondition checks + * be done before any linking and delinking happens. + * The final part (postReplaceChild )reports post-add events. + * <p> + * This method calls <code>ast.modifying()</code> for the nodes affected. + * </p> + * + * @param oldChild the old child of this node, or <code>null</code> if + * there was no old child to replace + * @param newChild the new child of this node, or <code>null</code> if + * there is no replacement child + * @param property the property descriptor of this node describing + * the relationship between node and child + * @exception RuntimeException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * <li>any of the nodes involved are unmodifiable</li> + * </ul> + * @since 3.0 + */ + final void preReplaceChild(ASTNode oldChild, ASTNode newChild, ChildPropertyDescriptor property) { + if ((this.typeAndFlags & PROTECT) != 0) { + // this node is protected => cannot gain or lose children + throw new IllegalArgumentException("AST node cannot be modified"); //$NON-NLS-1$ + } + if (newChild != null) { + checkNewChild(this, newChild, property.cycleRisk, null); + } + // delink old child from parent + if (oldChild != null) { + if ((oldChild.typeAndFlags & PROTECT) != 0) { + // old child node is protected => cannot be unparented + throw new IllegalArgumentException("AST node cannot be modified"); //$NON-NLS-1$ + } + if (newChild != null) { + this.ast.preReplaceChildEvent(this, oldChild, newChild, property); + } else { + this.ast.preRemoveChildEvent(this, oldChild, property); + } + oldChild.setParent(null, null); + } else { + if(newChild != null) { + this.ast.preAddChildEvent(this, newChild, property); + } + } + // link new child to parent + if (newChild != null) { + newChild.setParent(this, property); + // cannot notify postAddChildEvent until parent is linked to child too + } + } + + /** + * Postlude portion of the "3 step program" for replacing the + * old child of this node with another node. + * See {@link #preReplaceChild(ASTNode, ASTNode, ChildPropertyDescriptor)} + * for details. + * @since 3.0 + */ + final void postReplaceChild(ASTNode oldChild, ASTNode newChild, ChildPropertyDescriptor property) { + // link new child to parent + if (newChild != null) { + if (oldChild != null) { + this.ast.postReplaceChildEvent(this, oldChild, newChild, property); + } else { + this.ast.postAddChildEvent(this, newChild, property); + } + } else { + this.ast.postRemoveChildEvent(this, oldChild, property); + } + } + + /** + * Prelude portion of the "3 step program" for changing the + * value of a simple property of this node. + * Here is the code pattern found in all AST node subclasses: + * <pre> + * preValueChange(FOO_PROPERTY); + * this.foo = newFoo; + * postValueChange(FOO_PROPERTY); + * </pre> + * The first part (preValueChange) does the precondition check + * to make sure the node is modifiable (not PROTECTED). + * The change operation must fail atomically; so it is crucial + * that the precondition checks are done before the field is + * hammered. The final part (postValueChange)reports post-change + * events. + * <p> + * This method calls <code>ast.modifying()</code> for the node affected. + * </p> + * + * @param property the property descriptor of this node + * @exception RuntimeException if: + * <ul> + * <li>this node is unmodifiable</li> + * </ul> + * @since 3.0 + */ + final void preValueChange(SimplePropertyDescriptor property) { + if ((this.typeAndFlags & PROTECT) != 0) { + // this node is protected => cannot change valure of properties + throw new IllegalArgumentException("AST node cannot be modified"); //$NON-NLS-1$ + } + this.ast.preValueChangeEvent(this, property); + this.ast.modifying(); + } + + /** + * Postlude portion of the "3 step program" for replacing the + * old child of this node with another node. + * See {@link #preValueChange(SimplePropertyDescriptor)} for details. + * @since 3.0 + */ + final void postValueChange(SimplePropertyDescriptor property) { + this.ast.postValueChangeEvent(this, property); + } + + /** + * Ensures that this node is modifiable (that is, not marked PROTECTED). + * If successful, calls ast.modifying(). + * @exception RuntimeException is not modifiable + */ + final void checkModifiable() { + if ((this.typeAndFlags & PROTECT) != 0) { + throw new IllegalArgumentException("AST node cannot be modified"); //$NON-NLS-1$ + } + this.ast.modifying(); + } + + /** + * Begin lazy initialization of this node. + * Here is the code pattern found in all AST + * node subclasses: + * <pre> + * if (this.foo == null) { + * // lazy init must be thread-safe for readers + * synchronized (this) { + * if (this.foo == null) { + * preLazyInit(); + * this.foo = ...; // code to create new node + * postLazyInit(this.foo, FOO_PROPERTY); + * } + * } + * } + * </pre> + * @since 3.0 + */ + final void preLazyInit() { + // IMPORTANT: this method is called by readers + // ASTNode.this is locked at this point + this.ast.disableEvents(); + // will turn events back on in postLasyInit + } + + /** + * End lazy initialization of this node. + * + * @param newChild the new child of this node, or <code>null</code> if + * there is no replacement child + * @param property the property descriptor of this node describing + * the relationship between node and child + * @since 3.0 + */ + final void postLazyInit(ASTNode newChild, ChildPropertyDescriptor property) { + // IMPORTANT: this method is called by readers + // ASTNode.this is locked at this point + // newChild is brand new (so no chance of concurrent access) + newChild.setParent(this, property); + // turn events back on (they were turned off in corresponding preLazyInit) + this.ast.reenableEvents(); + } + + /** + * Returns the named property of this node, or <code>null</code> if none. + * + * @param propertyName the property name + * @return the property value, or <code>null</code> if none + * @see #setProperty(String,Object) + */ + public final Object getProperty(String propertyName) { + if (propertyName == null) { + throw new IllegalArgumentException(); + } + if (this.property1 == null) { + // node has no properties at all + return null; + } + if (this.property1 instanceof String) { + // node has only a single property + if (propertyName.equals(this.property1)) { + return this.property2; + } else { + return null; + } + } + // otherwise node has table of properties + Map m = (Map) this.property1; + return m.get(propertyName); + } + + /** + * Sets the named property of this node to the given value, + * or to <code>null</code> to clear it. + * <p> + * Clients should employ property names that are sufficiently unique + * to avoid inadvertent conflicts with other clients that might also be + * setting properties on the same node. + * </p> + * <p> + * Note that modifying a property is not considered a modification to the + * AST itself. This is to allow clients to decorate existing nodes with + * their own properties without jeopardizing certain things (like the + * validity of bindings), which rely on the underlying tree remaining static. + * </p> + * + * @param propertyName the property name + * @param data the new property value, or <code>null</code> if none + * @see #getProperty(String) + */ + public final void setProperty(String propertyName, Object data) { + if (propertyName == null) { + throw new IllegalArgumentException(); + } + // N.B. DO NOT CALL ast.modifying(); + + if (this.property1 == null) { + // node has no properties at all + if (data == null) { + // we already know this + return; + } + // node gets its fist property + this.property1 = propertyName; + this.property2 = data; + return; + } + + if (this.property1 instanceof String) { + // node has only a single property + if (propertyName.equals(this.property1)) { + // we're in luck + this.property2 = data; + if (data == null) { + // just deleted last property + this.property1 = null; + this.property2 = null; + } + return; + } + if (data == null) { + // we already know this + return; + } + // node already has one property - getting its second + // convert to more flexible representation + HashMap m = new HashMap(2); + m.put(this.property1, this.property2); + m.put(propertyName, data); + this.property1 = m; + this.property2 = null; + return; + } + + // node has two or more properties + HashMap m = (HashMap) this.property1; + if (data == null) { + m.remove(propertyName); + // check for just one property left + if (m.size() == 1) { + // convert to more efficient representation + Map.Entry[] entries = (Map.Entry[]) m.entrySet().toArray(new Map.Entry[1]); + this.property1 = entries[0].getKey(); + this.property2 = entries[0].getValue(); + } + return; + } else { + m.put(propertyName, data); + // still has two or more properties + return; + } + } + + /** + * Returns an unmodifiable table of the properties of this node with + * non-<code>null</code> values. + * + * @return the table of property values keyed by property name + * (key type: <code>String</code>; value type: <code>Object</code>) + */ + public final Map properties() { + if (this.property1 == null) { + // node has no properties at all + return UNMODIFIABLE_EMPTY_MAP; + } + if (this.property1 instanceof String) { + // node has a single property + return Collections.singletonMap(this.property1, this.property2); + } + + // node has two or more properties + if (this.property2 == null) { + this.property2 = Collections.unmodifiableMap((Map) this.property1); + } + // property2 is unmodifiable wrapper for map in property1 + return (Map) this.property2; + } + + /** + * Returns the flags associated with this node. + * <p> + * No flags are associated with newly created nodes. + * </p> + * <p> + * The flags are the bitwise-or of individual flags. + * The following flags are currently defined: + * <ul> + * <li>{@link #MALFORMED} - indicates node is syntactically + * malformed</li> + * <li>{@link #ORIGINAL} - indicates original node + * created by ASTParser</li> + * <li>{@link #PROTECT} - indicates node is protected + * from further modification</li> + * <li>{@link #RECOVERED} - indicates node or a part of this node + * is recovered from source that contains a syntax error</li> + * </ul> + * Other bit positions are reserved for future use. + * </p> + * + * @return the bitwise-or of individual flags + * @see #setFlags(int) + */ + public final int getFlags() { + return this.typeAndFlags & 0xFFFF; + } + + /** + * Sets the flags associated with this node to the given value. + * <p> + * The flags are the bitwise-or of individual flags. + * The following flags are currently defined: + * <ul> + * <li>{@link #MALFORMED} - indicates node is syntactically + * malformed</li> + * <li>{@link #ORIGINAL} - indicates original node + * created by ASTParser</li> + * <li>{@link #PROTECT} - indicates node is protected + * from further modification</li> + * <li>{@link #RECOVERED} - indicates node or a part of this node + * is recovered from source that contains a syntax error</li> + * </ul> + * Other bit positions are reserved for future use. + * </p> + * <p> + * Note that the flags are <em>not</em> considered a structural + * property of the node, and can be changed even if the + * node is marked as protected. + * </p> + * + * @param flags the bitwise-or of individual flags + * @see #getFlags() + */ + public final void setFlags(int flags) { + this.ast.modifying(); + int old = this.typeAndFlags & 0xFFFF0000; + this.typeAndFlags = old | (flags & 0xFFFF); + } + + /** + * Returns an integer value identifying the type of this concrete AST node. + * The values are small positive integers, suitable for use in switch statements. + * <p> + * For each concrete node type there is a unique node type constant (name + * and value). The unique node type constant for a concrete node type such as + * <code>CastExpression</code> is <code>ASTNode.CAST_EXPRESSION</code>. + * </p> + * + * @return one of the node type constants + */ + public final int getNodeType() { + return this.typeAndFlags >>> 16; + } + + /** + * Sets the integer value identifying the type of this concrete AST node. + * The values are small positive integers, suitable for use in switch statements. + * + * @param nodeType one of the node type constants + */ + private void setNodeType(int nodeType) { + int old = this.typeAndFlags & 0xFFFF0000; + this.typeAndFlags = old | (nodeType << 16); + } + + /** + * Returns an integer value identifying the type of this concrete AST node. + * <p> + * This internal method is implemented in each of the + * concrete node subclasses. + * </p> + * + * @return one of the node type constants + */ + abstract int getNodeType0(); + + /** + * The <code>ASTNode</code> implementation of this <code>Object</code> + * method uses object identity (==). Use <code>subtreeMatch</code> to + * compare two subtrees for equality. + * + * @param obj {@inheritDoc} + * @return {@inheritDoc} + * @see #subtreeMatch(ASTMatcher matcher, Object other) + */ + public final boolean equals(Object obj) { + return this == obj; // equivalent to Object.equals + } + + /* + * (non-Javadoc) + * This makes it consistent with the fact that a equals methods has been provided. + * @see java.lang.Object#hashCode() + */ + public final int hashCode() { + return super.hashCode(); + } + + /** + * Returns whether the subtree rooted at the given node matches the + * given other object as decided by the given matcher. + * + * @param matcher the matcher + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match + */ + public final boolean subtreeMatch(ASTMatcher matcher, Object other) { + return subtreeMatch0(matcher, other); + } + + /** + * Returns whether the subtree rooted at the given node matches the + * given other object as decided by the given matcher. + * <p> + * This internal method is implemented in each of the + * concrete node subclasses. + * </p> + * + * @param matcher the matcher + * @param other the other object, or <code>null</code> + * @return <code>true</code> if the subtree matches, or + * <code>false</code> if they do not match + */ + abstract boolean subtreeMatch0(ASTMatcher matcher, Object other); + + /** + * Returns a deep copy of the subtree of AST nodes rooted at the + * given node. The resulting nodes are owned by the given AST, + * which may be different from the ASTs of the given node. + * Even if the given node has a parent, the result node will be unparented. + * <p> + * Source range information on the original nodes is automatically copied to the new + * nodes. Client properties (<code>properties</code>) are not carried over. + * </p> + * <p> + * The node's <code>AST</code> and the target <code>AST</code> must support + * the same API level. + * </p> + * + * @param target the AST that is to own the nodes in the result + * @param node the node to copy, or <code>null</code> if none + * @return the copied node, or <code>null</code> if <code>node</code> + * is <code>null</code> + */ + public static ASTNode copySubtree(AST target, ASTNode node) { + if (node == null) { + return null; + } + if (target == null) { + throw new IllegalArgumentException(); + } + if (target.apiLevel() != node.getAST().apiLevel()) { + throw new UnsupportedOperationException(); + } + ASTNode newNode = node.clone(target); + return newNode; + } + + /** + * Returns a deep copy of the subtrees of AST nodes rooted at the + * given list of nodes. The resulting nodes are owned by the given AST, + * which may be different from the ASTs of the nodes in the list. + * Even if the nodes in the list have parents, the nodes in the result + * will be unparented. + * <p> + * Source range information on the original nodes is automatically copied to the new + * nodes. Client properties (<code>properties</code>) are not carried over. + * </p> + * + * @param target the AST that is to own the nodes in the result + * @param nodes the list of nodes to copy + * (element type: <code>ASTNode</code>) + * @return the list of copied subtrees + * (element type: <code>ASTNode</code>) + */ + public static List copySubtrees(AST target, List nodes) { + List result = new ArrayList(nodes.size()); + for (Iterator it = nodes.iterator(); it.hasNext(); ) { + ASTNode oldNode = (ASTNode) it.next(); + ASTNode newNode = oldNode.clone(target); + result.add(newNode); + } + return result; + } + + /** + * Returns a deep copy of the subtree of AST nodes rooted at this node. + * The resulting nodes are owned by the given AST, which may be different + * from the AST of this node. Even if this node has a parent, the + * result node will be unparented. + * <p> + * This method reports pre- and post-clone events, and dispatches + * to <code>clone0(AST)</code> which is reimplemented in node subclasses. + * </p> + * + * @param target the AST that is to own the nodes in the result + * @return the root node of the copies subtree + */ + final ASTNode clone(AST target) { + this.ast.preCloneNodeEvent(this); + ASTNode c = clone0(target); + this.ast.postCloneNodeEvent(this, c); + return c; + } + + /** + * Returns a deep copy of the subtree of AST nodes rooted at this node. + * The resulting nodes are owned by the given AST, which may be different + * from the AST of this node. Even if this node has a parent, the + * result node will be unparented. + * <p> + * This method must be implemented in subclasses. + * </p> + * <p> + * This method does not report pre- and post-clone events. + * All callers should instead call <code>clone(AST)</code> + * to ensure that pre- and post-clone events are reported. + * </p> + * <p> + * N.B. This method is package-private, so that the implementations + * of this method in each of the concrete AST node types do not + * clutter up the API doc. + * </p> + * + * @param target the AST that is to own the nodes in the result + * @return the root node of the copies subtree + */ + abstract ASTNode clone0(AST target); + + /** + * Accepts the given visitor on a visit of the current node. + * + * @param visitor the visitor object + * @exception IllegalArgumentException if the visitor is null + */ + public final void accept(ASTVisitor visitor) { + if (visitor == null) { + throw new IllegalArgumentException(); + } + // begin with the generic pre-visit + if (visitor.preVisit2(this)) { + // dynamic dispatch to internal method for type-specific visit/endVisit + accept0(visitor); + } + // end with the generic post-visit + visitor.postVisit(this); + } + + /** + * Accepts the given visitor on a type-specific visit of the current node. + * This method must be implemented in all concrete AST node types. + * <p> + * General template for implementation on each concrete ASTNode class: + * <pre> + * <code> + * boolean visitChildren = visitor.visit(this); + * if (visitChildren) { + * // visit children in normal left to right reading order + * acceptChild(visitor, getProperty1()); + * acceptChildren(visitor, rawListProperty); + * acceptChild(visitor, getProperty2()); + * } + * visitor.endVisit(this); + * </code> + * </pre> + * Note that the caller (<code>accept</code>) take cares of invoking + * <code>visitor.preVisit(this)</code> and <code>visitor.postVisit(this)</code>. + * </p> + * + * @param visitor the visitor object + */ + abstract void accept0(ASTVisitor visitor); + + /** + * Accepts the given visitor on a visit of the current node. + * <p> + * This method should be used by the concrete implementations of + * <code>accept0</code> to traverse optional properties. Equivalent + * to <code>child.accept(visitor)</code> if <code>child</code> + * is not <code>null</code>. + * </p> + * + * @param visitor the visitor object + * @param child the child AST node to dispatch too, or <code>null</code> + * if none + */ + final void acceptChild(ASTVisitor visitor, ASTNode child) { + if (child == null) { + return; + } + child.accept(visitor); + } + + /** + * Accepts the given visitor on a visit of the given live list of + * child nodes. + * <p> + * This method must be used by the concrete implementations of + * <code>accept</code> to traverse list-values properties; it + * encapsulates the proper handling of on-the-fly changes to the list. + * </p> + * + * @param visitor the visitor object + * @param children the child AST node to dispatch too, or <code>null</code> + * if none + */ + final void acceptChildren(ASTVisitor visitor, ASTNode.NodeList children) { + // use a cursor to keep track of where we are up to + // (the list may be changing under foot) + if(children != null) { + NodeList.Cursor cursor = children.newCursor(); + try { + while (cursor.hasNext()) { + ASTNode child = (ASTNode) cursor.next(); + child.accept(visitor); + } + } finally { + children.releaseCursor(cursor); + } + } + } + + /** + * Returns the character index into the original source file indicating + * where the source fragment corresponding to this node begins. + * <p> + * The parser supplies useful well-defined source ranges to the nodes it creates. + * See {@link ASTParser#setKind(int)} for details + * on precisely where source ranges begin and end. + * </p> + * + * @return the 0-based character index, or <code>-1</code> + * if no source position information is recorded for this node + * @see #getLength() + * @see ASTParser + */ + public final int getStartPosition() { + return this.startPosition; + } + + /** + * Returns the length in characters of the original source file indicating + * where the source fragment corresponding to this node ends. + * <p> + * The parser supplies useful well-defined source ranges to the nodes it creates. + * See {@link ASTParser#setKind(int)} methods for details + * on precisely where source ranges begin and end. + * </p> + * + * @return a (possibly 0) length, or <code>0</code> + * if no source position information is recorded for this node + * @see #getStartPosition() + * @see ASTParser + */ + public final int getLength() { + return this.length; + } + + /** + * Sets the source range of the original source file where the source + * fragment corresponding to this node was found. + * <p> + * See {@link ASTParser#setKind(int)} for details + * on precisely where source ranges are supposed to begin and end. + * </p> + * + * @param startPosition a 0-based character index, + * or <code>-1</code> if no source position information is + * available for this node + * @param length a (possibly 0) length, + * or <code>0</code> if no source position information is recorded + * for this node + * @see #getStartPosition() + * @see #getLength() + * @see ASTParser + */ + public final void setSourceRange(int startPosition, int length) { + if (startPosition >= 0 && length < 0) { + throw new IllegalArgumentException(); + } + if (startPosition < 0 && length != 0) { + throw new IllegalArgumentException(); + } + // source positions are not considered a structural property + // but we protect them nevertheless + checkModifiable(); + this.startPosition = startPosition; + this.length = length; + } + + /** + * Returns a string representation of this node suitable for debugging + * purposes only. + * + * @return a debug string + */ + public final String toString() { + StringBuffer buffer = new StringBuffer(); + int p = buffer.length(); + try { + appendDebugString(buffer); + } catch (RuntimeException e) { + // since debugger sometimes call toString methods, problems can easily happen when + // toString is called on an instance that is being initialized + buffer.setLength(p); + buffer.append("!"); //$NON-NLS-1$ + buffer.append(standardToString()); + } + return buffer.toString(); + } + + /** + * Returns the string representation of this node produced by the standard + * <code>Object.toString</code> method. + * + * @return a debug string + */ + final String standardToString() { + return super.toString(); + } + + /** + * Appends a debug representation of this node to the given string buffer. + * <p> + * The <code>ASTNode</code> implementation of this method prints out the entire + * subtree. Subclasses may override to provide a more succinct representation. + * </p> + * + * @param buffer the string buffer to append to + */ + void appendDebugString(StringBuffer buffer) { + // print the subtree by default + appendPrintString(buffer); + } + + /** + * Appends a standard Java source code representation of this subtree to the given + * string buffer. + * + * @param buffer the string buffer to append to + */ + final void appendPrintString(StringBuffer buffer) { + NaiveASTFlattener printer = new NaiveASTFlattener(); + accept(printer); + buffer.append(printer.getResult()); + } + + /** + * Estimate of size of an object header in bytes. + */ + static final int HEADERS = 12; + + /** + * Approximate base size of an AST node instance in bytes, + * including object header and instance fields. + * That is, HEADERS + (# instance vars in ASTNode)*4. + */ + static final int BASE_NODE_SIZE = HEADERS + 7 * 4; + + /** + * Returns an estimate of the memory footprint, in bytes, + * of the given string. + * + * @param string the string to measure, or <code>null</code> + * @return the size of this string object in bytes, or + * 0 if the string is <code>null</code> + * @since 3.0 + */ + static int stringSize(String string) { + int size = 0; + if (string != null) { + // Strings usually have 4 instance fields, one of which is a char[] + size += HEADERS + 4 * 4; + // char[] has 2 bytes per character + size += HEADERS + 2 * string.length(); + } + return size; + } + + /** + * Returns an estimate of the memory footprint in bytes of the entire + * subtree rooted at this node. + * + * @return the size of this subtree in bytes + */ + public final int subtreeBytes() { + return treeSize(); + } + + /** + * Returns an estimate of the memory footprint in bytes of the entire + * subtree rooted at this node. + * <p> + * N.B. This method is package-private, so that the implementations + * of this method in each of the concrete AST node types do not + * clutter up the API doc. + * </p> + * + * @return the size of this subtree in bytes + */ + abstract int treeSize(); + + /** + * Returns an estimate of the memory footprint of this node in bytes. + * The estimate does not include the space occupied by child nodes. + * + * @return the size of this node in bytes + */ + abstract int memSize(); +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTParser.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTParser.java new file mode 100644 index 000000000..9da9740d1 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTParser.java @@ -0,0 +1,1252 @@ +/******************************************************************************* + * Copyright (c) 2004, 2009 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 + * $Id: ASTParser.java 23401 2010-02-02 23:56:05Z stephan $ + * + * Contributors: + * IBM Corporation - initial API and implementation + * Fraunhofer FIRST - extended API and implementation + * Technical University Berlin - extended API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.dom; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jdt.core.IClassFile; +import org.eclipse.jdt.core.ICompilationUnit; +import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.core.ITypeRoot; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.core.WorkingCopyOwner; +import org.eclipse.jdt.core.compiler.CategorizedProblem; +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; +import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration; +import org.eclipse.jdt.internal.compiler.env.IBinaryType; +import org.eclipse.jdt.internal.compiler.parser.RecoveryScanner; +import org.eclipse.jdt.internal.compiler.parser.RecoveryScannerData; +import org.eclipse.jdt.internal.compiler.parser.Scanner; +import org.eclipse.jdt.internal.compiler.util.SuffixConstants; +import org.eclipse.jdt.internal.core.*; +import org.eclipse.jdt.internal.core.util.CodeSnippetParsingUtil; +import org.eclipse.jdt.internal.core.util.RecordedParsingInformation; +import org.eclipse.jdt.internal.core.util.Util; +import org.eclipse.objectteams.otdt.core.exceptions.InternalCompilerError; + +/** + * A Java language parser for creating abstract syntax trees (ASTs). + * <p> + * Example: Create basic AST from source string + * <pre> + * char[] source = ...; + * ASTParser parser = ASTParser.newParser(AST.JLS3); // handles JDK 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6 + * parser.setSource(source); + * CompilationUnit result = (CompilationUnit) parser.createAST(null); + * </pre> + * Once a configured parser instance has been used to create an AST, + * the settings are automatically reset to their defaults, + * ready for the parser instance to be reused. + * </p> + * <p> + * There are a number of configurable features: + * <ul> + * <li>Source string from {@link #setSource(char[]) char[]}, + * {@link #setSource(ICompilationUnit) ICompilationUnit}, + * or {@link #setSource(IClassFile) IClassFile}, and limited + * to a specified {@linkplain #setSourceRange(int,int) subrange}.</li> + * <li>Whether {@linkplain #setResolveBindings(boolean) bindings} will be created.</li> + * <li>Which {@linkplain #setWorkingCopyOwner(WorkingCopyOwner) + * working copy owner} to use when resolving bindings.</li> + * <li>A hypothetical {@linkplain #setUnitName(String) compilation unit file name} + * and {@linkplain #setProject(IJavaProject) Java project} + * for locating a raw source string in the Java model (when + * resolving bindings)</li> + * <li>Which {@linkplain #setCompilerOptions(Map) compiler options} + * to use. This is especially important to use if the parsing/scanning of the source code requires a + * different version than the default of the workspace. For example, the workspace defaults are 1.4 and + * you want to create an AST for a source code that is using 1.5 constructs.</li> + * <li>Whether to parse just {@linkplain #setKind(int) an expression, statements, + * or body declarations} rather than an entire compilation unit.</li> + * <li>Whether to return a {@linkplain #setFocalPosition(int) abridged AST} + * focused on the declaration containing a given source position.</li> + * </ul> + * </p> + * + * @since 3.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +@SuppressWarnings("unchecked") +public class ASTParser { + + /** + * Kind constant used to request that the source be parsed + * as a single expression. + */ + public static final int K_EXPRESSION = 0x01; + + /** + * Kind constant used to request that the source be parsed + * as a sequence of statements. + */ + public static final int K_STATEMENTS = 0x02; + + /** + * Kind constant used to request that the source be parsed + * as a sequence of class body declarations. + */ + public static final int K_CLASS_BODY_DECLARATIONS = 0x04; + + /** + * Kind constant used to request that the source be parsed + * as a compilation unit. + */ + public static final int K_COMPILATION_UNIT = 0x08; + + /** + * Creates a new object for creating a Java abstract syntax tree + * (AST) following the specified set of API rules. + * + * @param level the API level; one of the LEVEL constants + * declared on <code>AST</code> + * @return new ASTParser instance + */ + public static ASTParser newParser(int level) { + return new ASTParser(level); + } + + /** + * Level of AST API desired. + */ + private final int apiLevel; + + /** + * Kind of parse requested. Defaults to an entire compilation unit. + */ + private int astKind; + + /** + * Compiler options. Defaults to JavaCore.getOptions(). + */ + private Map compilerOptions; + + /** + * Request for bindings. Defaults to <code>false</code>. + */ + private boolean resolveBindings; + + /** + * Request for a partial AST. Defaults to <code>false</code>. + */ + private boolean partial = false; + + /** + * Request for a statements recovery. Defaults to <code>false</code>. + */ + private boolean statementsRecovery; + + /** + * Request to ignore parsing the method bodies. Defaults to <code>false</code>. + */ + private boolean ignoreMethodBodies; + /** + * Request for a bindings recovery. Defaults to <code>false</code>. + */ + private boolean bindingsRecovery; + + /** + * The focal point for a partial AST request. + * Only used when <code>partial</code> is <code>true</code>. + */ + private int focalPointPosition; + + /** + * Source string. + */ + private char[] rawSource = null; + + /** + * Java model class file or compilation unit supplying the source. + */ + private ITypeRoot typeRoot = null; + + /** + * Character-based offset into the source string where parsing is to + * begin. Defaults to 0. + */ + private int sourceOffset = 0; + + /** + * Character-based length limit, or -1 if unlimited. + * All characters in the source string between <code>offset</code> + * and <code>offset+length-1</code> inclusive are parsed. Defaults to -1, + * which means the rest of the source string. + */ + private int sourceLength = -1; + + /** + * Working copy owner. Defaults to primary owner. + */ + private WorkingCopyOwner workingCopyOwner = DefaultWorkingCopyOwner.PRIMARY; + + /** + * Java project used to resolve names, or <code>null</code> if none. + * Defaults to none. + */ + private IJavaProject project = null; + + /** + * Name of the compilation unit for resolving bindings, or + * <code>null</code> if none. Defaults to none. + */ + private String unitName = null; + + /** + * Creates a new AST parser for the given API level. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param level the API level; one of the LEVEL constants + * declared on <code>AST</code> + */ + ASTParser(int level) { + if ((level != AST.JLS2_INTERNAL) + && (level != AST.JLS3)) { + throw new IllegalArgumentException(); + } + this.apiLevel = level; + initializeDefaults(); + } + + /** + * Sets all the setting to their default values. + */ + private void initializeDefaults() { + this.astKind = K_COMPILATION_UNIT; + this.rawSource = null; + this.typeRoot = null; + this.resolveBindings = false; + this.ignoreMethodBodies = false; + this.sourceLength = -1; + this.sourceOffset = 0; + this.workingCopyOwner = DefaultWorkingCopyOwner.PRIMARY; + this.unitName = null; + this.project = null; + this.partial = false; + Map options = JavaCore.getOptions(); + options.remove(JavaCore.COMPILER_TASK_TAGS); // no need to parse task tags + this.compilerOptions = options; + } + + /** + * Requests that the compiler should perform bindings recovery. + * When bindings recovery is enabled the compiler returns incomplete bindings. + * <p> + * Default to <code>false</code>. + * </p> + * <p>This should be set to true only if bindings are resolved. It has no effect if there is no binding + * resolution.</p> + * + * @param enabled <code>true</code> if incomplete bindings are expected, + * and <code>false</code> if only complete bindings are expected. + * + * @see IBinding#isRecovered() + * @since 3.3 + */ + public void setBindingsRecovery(boolean enabled) { + this.bindingsRecovery = enabled; + } + /** + * Sets the compiler options to be used when parsing. + * <p> + * Note that {@link #setSource(IClassFile)}, + * {@link #setSource(ICompilationUnit)}, + * and {@link #setProject(IJavaProject)} reset the compiler options + * based on the Java project. In other cases, compiler options default + * to {@link JavaCore#getOptions()}. In either case, and especially + * in the latter, the caller should carefully weight the consequences of + * allowing compiler options to be defaulted as opposed to being + * explicitly specified for the <code>ASTParser</code> instance. + * For instance, there is a compiler option called "Source Compatibility Mode" + * which determines which JDK level the source code is expected to meet. + * If you specify "1.4", then "assert" is treated as a keyword and disallowed + * as an identifier; if you specify "1.3", then "assert" is allowed as an + * identifier. So this particular setting has a major bearing on what is + * considered syntactically legal. By explicitly specifying the setting, + * the client control exactly how the parser works. On the other hand, + * allowing default settings means the parsing behaves like other JDT tools. + * </p> + * + * @param options the table of options (key type: <code>String</code>; + * value type: <code>String</code>), or <code>null</code> + * to set it back to the default + */ + public void setCompilerOptions(Map options) { + if (options == null) { + options = JavaCore.getOptions(); + } else { + // copy client's options so as to not do any side effect on them + options = new HashMap(options); + } + options.remove(JavaCore.COMPILER_TASK_TAGS); // no need to parse task tags + this.compilerOptions = options; + } + + /** + * Requests that the compiler should provide binding information for + * the AST nodes it creates. + * <p> + * Default to <code>false</code> (no bindings). + * </p> + * <p> + * If <code>setResolveBindings(true)</code>, the various names + * and types appearing in the AST can be resolved to "bindings" + * by calling the <code>resolveBinding</code> methods. These bindings + * draw connections between the different parts of a program, and + * generally afford a more powerful vantage point for clients who wish to + * analyze a program's structure more deeply. These bindings come at a + * considerable cost in both time and space, however, and should not be + * requested frivolously. The additional space is not reclaimed until the + * AST, all its nodes, and all its bindings become garbage. So it is very + * important to not retain any of these objects longer than absolutely + * necessary. Bindings are resolved at the time the AST is created. Subsequent + * modifications to the AST do not affect the bindings returned by + * <code>resolveBinding</code> methods in any way; these methods return the + * same binding as before the AST was modified (including modifications + * that rearrange subtrees by reparenting nodes). + * If <code>setResolveBindings(false)</code> (the default), the analysis + * does not go beyond parsing and building the tree, and all + * <code>resolveBinding</code> methods return <code>null</code> from the + * outset. + * </p> + * <p> + * When bindings are requested, instead of considering compilation units on disk only + * one can supply a <code>WorkingCopyOwner</code>. Working copies owned + * by this owner take precedence over the underlying compilation units when looking + * up names and drawing the connections. + * </p> + * <p> + * Binding information is obtained from the Java model. + * This means that the compilation unit must be located relative to the + * Java model. This happens automatically when the source code comes from + * either {@link #setSource(ICompilationUnit) setSource(ICompilationUnit)} + * or {@link #setSource(IClassFile) setSource(IClassFile)}. + * When source is supplied by {@link #setSource(char[]) setSource(char[])}, + * the location must be extablished explicitly by calling + * {@link #setProject(IJavaProject)} and {@link #setUnitName(String)}. + * Note that the compiler options that affect doc comment checking may also + * affect whether any bindings are resolved for nodes within doc comments. + * </p> + * + * @param bindings <code>true</code> if bindings are wanted, + * and <code>false</code> if bindings are not of interest + */ + public void setResolveBindings(boolean bindings) { + this.resolveBindings = bindings; + } + + /** + * Requests an abridged abstract syntax tree. + * By default, complete ASTs are returned. + * <p> + * When <code>true</code> the resulting AST does not have nodes for + * the entire compilation unit. Rather, the AST is only fleshed out + * for the node that include the given source position. This kind of limited + * AST is sufficient for certain purposes but totally unsuitable for others. + * In places where it can be used, the limited AST offers the advantage of + * being smaller and faster to construct. + * </p> + * <p> + * The AST will include nodes for all of the compilation unit's + * package, import, and top-level type declarations. It will also always contain + * nodes for all the body declarations for those top-level types, as well + * as body declarations for any member types. However, some of the body + * declarations may be abridged. In particular, the statements ordinarily + * found in the body of a method declaration node will not be included + * (the block will be empty) unless the source position falls somewhere + * within the source range of that method declaration node. The same is true + * for initializer declarations; the statements ordinarily found in the body + * of initializer node will not be included unless the source position falls + * somewhere within the source range of that initializer declaration node. + * Field declarations are never abridged. Note that the AST for the body of + * that one unabridged method (or initializer) is 100% complete; it has all + * its statements, including any local or anonymous type declarations + * embedded within them. When the the given position is not located within + * the source range of any body declaration of a top-level type, the AST + * returned will be a skeleton that includes nodes for all and only the major + * declarations; this kind of AST is still quite useful because it contains + * all the constructs that introduce names visible to the world outside the + * compilation unit. + * </p> + * + * <p>This focal position is not used when the AST is built using + * {@link #createASTs(ICompilationUnit[], String[], ASTRequestor, IProgressMonitor)}.</p> + * + * @param position a position into the corresponding body declaration + */ + public void setFocalPosition(int position) { + this.partial = true; + this.focalPointPosition = position; + } + + /** + * Sets the kind of constructs to be parsed from the source. + * Defaults to an entire compilation unit. + * <p> + * When the parse is successful the result returned includes the ASTs for the + * requested source: + * <ul> + * <li>{@link #K_COMPILATION_UNIT K_COMPILATION_UNIT}: The result node + * is a {@link CompilationUnit}.</li> + * <li>{@link #K_CLASS_BODY_DECLARATIONS K_CLASS_BODY_DECLARATIONS}: The result node + * is a {@link TypeDeclaration} whose + * {@link TypeDeclaration#bodyDeclarations() bodyDeclarations} + * are the new trees. Other aspects of the type declaration are unspecified.</li> + * <li>{@link #K_STATEMENTS K_STATEMENTS}: The result node is a + * {@link Block Block} whose {@link Block#statements() statements} + * are the new trees. Other aspects of the block are unspecified.</li> + * <li>{@link #K_EXPRESSION K_EXPRESSION}: The result node is a subclass of + * {@link Expression Expression}. Other aspects of the expression are unspecified.</li> + * </ul> + * The resulting AST node is rooted under (possibly contrived) + * {@link CompilationUnit CompilationUnit} node, to allow the + * client to retrieve the following pieces of information + * available there: + * <ul> + * <li>{@linkplain CompilationUnit#getLineNumber(int) Line number map}. Line + * numbers start at 1 and only cover the subrange scanned + * (<code>source[offset]</code> through <code>source[offset+length-1]</code>).</li> + * <li>{@linkplain CompilationUnit#getMessages() Compiler messages} + * and {@linkplain CompilationUnit#getProblems() detailed problem reports}. + * Character positions are relative to the start of + * <code>source</code>; line positions are for the subrange scanned.</li> + * <li>{@linkplain CompilationUnit#getCommentList() Comment list} + * for the subrange scanned.</li> + * </ul> + * The contrived nodes do not have source positions. Other aspects of the + * {@link CompilationUnit CompilationUnit} node are unspecified, including + * the exact arrangement of intervening nodes. + * </p> + * <p> + * Lexical or syntax errors detected while parsing can result in + * a result node being marked as {@link ASTNode#MALFORMED MALFORMED}. + * In more severe failure cases where the parser is unable to + * recognize the input, this method returns + * a {@link CompilationUnit CompilationUnit} node with at least the + * compiler messages. + * </p> + * <p>Each node in the subtree (other than the contrived nodes) + * carries source range(s) information relating back + * to positions in the given source (the given source itself + * is not remembered with the AST). + * The source range usually begins at the first character of the first token + * corresponding to the node; leading whitespace and comments are <b>not</b> + * included. The source range usually extends through the last character of + * the last token corresponding to the node; trailing whitespace and + * comments are <b>not</b> included. There are a handful of exceptions + * (including the various body declarations); the + * specification for these node type spells out the details. + * Source ranges nest properly: the source range for a child is always + * within the source range of its parent, and the source ranges of sibling + * nodes never overlap. + * </p> + * <p> + * Binding information is only computed when <code>kind</code> is + * <code>K_COMPILATION_UNIT</code>. + * </p> + * + * <p>This kind is not used when the AST is built using + * {@link #createASTs(ICompilationUnit[], String[], ASTRequestor, IProgressMonitor)}.</p> + * + * @param kind the kind of construct to parse: one of + * {@link #K_COMPILATION_UNIT}, + * {@link #K_CLASS_BODY_DECLARATIONS}, + * {@link #K_EXPRESSION}, + * {@link #K_STATEMENTS} + */ + public void setKind(int kind) { + if ((kind != K_COMPILATION_UNIT) + && (kind != K_CLASS_BODY_DECLARATIONS) + && (kind != K_EXPRESSION) + && (kind != K_STATEMENTS)) { + throw new IllegalArgumentException(); + } + this.astKind = kind; + } + + /** + * Sets the source code to be parsed. + * + * <p>This source is not used when the AST is built using + * {@link #createASTs(ICompilationUnit[], String[], ASTRequestor, IProgressMonitor)}.</p> + * + * @param source the source string to be parsed, + * or <code>null</code> if none + */ + public void setSource(char[] source) { + this.rawSource = source; + // clear the type root + this.typeRoot = null; + } + + /** + * Sets the source code to be parsed. + * This method automatically sets the project (and compiler + * options) based on the given compilation unit, in a manner + * equivalent to <code>setProject(source.getJavaProject())</code> + * + * <p>This source is not used when the AST is built using + * {@link #createASTs(ICompilationUnit[], String[], ASTRequestor, IProgressMonitor)}.</p> + * + * @param source the Java model compilation unit whose source code + * is to be parsed, or <code>null</code> if none + */ + public void setSource(ICompilationUnit source) { + setSource((ITypeRoot)source); + } + + /** + * Sets the source code to be parsed. + * <p>This method automatically sets the project (and compiler + * options) based on the given compilation unit, in a manner + * equivalent to <code>setProject(source.getJavaProject())</code>.</p> + * <p>If the given class file has no source attachment, the creation of the + * ast will fail with an IllegalStateException.</p> + * + * <p>This source is not used when the AST is built using + * {@link #createASTs(ICompilationUnit[], String[], ASTRequestor, IProgressMonitor)}.</p> + * + * @param source the Java model class file whose corresponding source code + * is to be parsed, or <code>null</code> if none + */ + public void setSource(IClassFile source) { + setSource((ITypeRoot)source); + } + + /** + * Sets the source code to be parsed. + * <p>This method automatically sets the project (and compiler + * options) based on the given compilation unit of class file, in a manner + * equivalent to <code>setProject(source.getJavaProject())</code>.</p> + * <p>If the source is a class file without source attachment, the creation of the + * ast will fail with an IllegalStateException.</p> + * + * <p>This source is not used when the AST is built using + * {@link #createASTs(ICompilationUnit[], String[], ASTRequestor, IProgressMonitor)}.</p> + * + * @param source the Java model compilation unit or class file whose corresponding source code + * is to be parsed, or <code>null</code> if none + * @since 3.3 + */ + public void setSource(ITypeRoot source) { + this.typeRoot = source; + // clear the raw source + this.rawSource = null; + if (source != null) { + this.project = source.getJavaProject(); + Map options = this.project.getOptions(true); + options.remove(JavaCore.COMPILER_TASK_TAGS); // no need to parse task tags + this.compilerOptions = options; + } + } + + /** + * Sets the subrange of the source code to be parsed. + * By default, the entire source string will be parsed + * (<code>offset</code> 0 and <code>length</code> -1). + * + * <p>This range is not used when the AST is built using + * {@link #createASTs(ICompilationUnit[], String[], ASTRequestor, IProgressMonitor)}.</p> + * + * @param offset the index of the first character to parse + * @param length the number of characters to parse, or -1 if + * the remainder of the source string is to be parsed + */ + public void setSourceRange(int offset, int length) { + if (offset < 0 || length < -1) { + throw new IllegalArgumentException(); + } + this.sourceOffset = offset; + this.sourceLength = length; + } + + /** + * Requests that the compiler should perform statements recovery. + * When statements recovery is enabled the compiler tries to create statement nodes + * from code containing syntax errors + * <p> + * Default to <code>false</code>. + * </p> + * + * @param enabled <code>true</code> if statements containing syntax errors are wanted, + * and <code>false</code> if these statements aren't wanted. + * + * @since 3.2 + */ + public void setStatementsRecovery(boolean enabled) { + this.statementsRecovery = enabled; + } + + /** + * Requests an abstract syntax tree without method bodies. + * + * <p>When ignore method bodies is enabled, all method bodies are discarded. + * This has no impact on the binding resolution.</p> + * + * <p>This setting is not used when the kind used in {@link #setKind(int)} is either + * {@link #K_EXPRESSION} or {@link #K_STATEMENTS}.</p> + * @since 3.5.2 + */ + public void setIgnoreMethodBodies(boolean enabled) { + this.ignoreMethodBodies = enabled; + } + + /** + * Sets the working copy owner using when resolving bindings, where + * <code>null</code> means the primary owner. Defaults to the primary owner. + * + * @param owner the owner of working copies that take precedence over underlying + * compilation units, or <code>null</code> if the primary owner should be used + */ + public void setWorkingCopyOwner(WorkingCopyOwner owner) { + if (owner == null) { + this.workingCopyOwner = DefaultWorkingCopyOwner.PRIMARY; + } else { + this.workingCopyOwner = owner; + } + } + + /** + * Sets the name of the compilation unit that would hypothetically contains + * the source string. This is used in conjunction with {@link #setSource(char[])} + * and {@link #setProject(IJavaProject) } to locate the compilation unit relative to a Java project. + * Defaults to none (<code>null</code>). + * <p> + * The name of the compilation unit must be supplied for resolving bindings. + * This name should be suffixed by a dot ('.') followed by one of the + * {@link JavaCore#getJavaLikeExtensions() Java-like extensions} + * and match the name of the main (public) class or interface declared in the source.</p> + * + * <p>This name must represent the full path of the unit inside the given project. For example, if the source + * declares a public class named "Foo" in a project "P" where the source folder is the project itself, the name + * of the compilation unit must be "/P/Foo.java". + * If the source declares a public class name "Bar" in a package "p1.p2" in a project "P" in a source folder "src", + * the name of the compilation unit must be "/P/src/p1/p2/Bar.java".</p> + * + * <p>This unit name is not used when the AST is built using + * {@link #createASTs(ICompilationUnit[], String[], ASTRequestor, IProgressMonitor)}.</p> + * + * @param unitName the name of the compilation unit that would contain the source + * string, or <code>null</code> if none + */ + public void setUnitName(String unitName) { + this.unitName = unitName; + } + + /** + * Sets the Java project used when resolving bindings. + * This method automatically sets the compiler + * options based on the given project: + * <pre> + * setCompilerOptions(project.getOptions(true)); + * </pre> + * See {@link #setCompilerOptions(Map)} for a discussion of + * the pros and cons of using these options vs specifying + * compiler options explicitly. + * This setting is used in conjunction with <code>setSource(char[])</code>. + * For the purposes of resolving bindings, types declared in the + * source string will hide types by the same name available + * through the classpath of the given project. + * Defaults to none (<code>null</code>). + * + * @param project the Java project used to resolve names, or + * <code>null</code> if none + */ + public void setProject(IJavaProject project) { + this.project = project; + if (project != null) { + Map options = project.getOptions(true); + options.remove(JavaCore.COMPILER_TASK_TAGS); // no need to parse task tags + this.compilerOptions = options; + } + } + + /** + * Creates an abstract syntax tree. + * <p> + * A successful call to this method returns all settings to their + * default values so the object is ready to be reused. + * </p> + * + * @param monitor the progress monitor used to report progress and request cancelation, + * or <code>null</code> if none + * @return an AST node whose type depends on the kind of parse + * requested, with a fallback to a <code>CompilationUnit</code> + * in the case of severe parsing errors + * @exception IllegalStateException if the settings provided + * are insufficient, contradictory, or otherwise unsupported + */ + public ASTNode createAST(IProgressMonitor monitor) { + ASTNode result = null; + if (monitor != null) monitor.beginTask("", 1); //$NON-NLS-1$ + try { + if (this.rawSource == null && this.typeRoot == null) { + throw new IllegalStateException("source not specified"); //$NON-NLS-1$ + } + result = internalCreateAST(monitor); + } finally { + // re-init defaults to allow reuse (and avoid leaking) + initializeDefaults(); + if (monitor != null) monitor.done(); + } + return result; + } + + /** + * Creates ASTs for a batch of compilation units. + * When bindings are being resolved, processing a + * batch of compilation units is more efficient because much + * of the work involved in resolving bindings can be shared. + * <p> + * When bindings are being resolved, all compilation units must + * come from the same Java project, which must be set beforehand + * with <code>setProject</code>. + * The compilation units are processed one at a time in no + * specified order. For each of the compilation units in turn, + * <ul> + * <li><code>ASTParser.createAST</code> is called to parse it + * and create a corresponding AST. The calls to + * <code>ASTParser.createAST</code> all employ the same settings.</li> + * <li><code>ASTRequestor.acceptAST</code> is called passing + * the compilation unit and the corresponding AST to + * <code>requestor</code>. + * </li> + * </ul> + * Note only ASTs from the given compilation units are reported + * to the requestor. If additional compilation units are required to + * resolve the original ones, the corresponding ASTs are <b>not</b> + * reported to the requestor. + * </p> + * <p> + * Note also the following parser parameters are used, regardless of what + * may have been specified: + * <ul> + * <li>The {@linkplain #setKind(int) parser kind} is <code>K_COMPILATION_UNIT</code></li> + * <li>The {@linkplain #setSourceRange(int,int) source range} is <code>(0, -1)</code></li> + * <li>The {@linkplain #setFocalPosition(int) focal position} is not set</li> + * </ul> + * </p> + * <p> + * The <code>bindingKeys</code> parameter specifies bindings keys + * ({@link IBinding#getKey()}) that are to be looked up. These keys may + * be for elements either inside or outside the set of compilation + * units being processed. When bindings are being resolved, + * the keys and corresponding bindings (or <code>null</code> if none) are + * passed to <code>ASTRequestor.acceptBinding</code>. Note that binding keys + * for elements outside the set of compilation units being processed are looked up + * after all <code>ASTRequestor.acceptAST</code> callbacks have been made. + * Binding keys for elements inside the set of compilation units being processed + * are looked up and reported right after the corresponding + * <code>ASTRequestor.acceptAST</code> callback has been made. + * No <code>ASTRequestor.acceptBinding</code> callbacks are made unless + * bindings are being resolved. + * </p> + * <p> + * A successful call to this method returns all settings to their + * default values so the object is ready to be reused. + * </p> + * + * @param compilationUnits the compilation units to create ASTs for + * @param bindingKeys the binding keys to create bindings for + * @param requestor the AST requestor that collects abstract syntax trees and bindings + * @param monitor the progress monitor used to report progress and request cancellation, + * or <code>null</code> if none + * @exception IllegalStateException if the settings provided + * are insufficient, contradictory, or otherwise unsupported + * @since 3.1 + */ + public void createASTs(ICompilationUnit[] compilationUnits, String[] bindingKeys, ASTRequestor requestor, IProgressMonitor monitor) { + try { + int flags = 0; + if (this.statementsRecovery) flags |= ICompilationUnit.ENABLE_STATEMENTS_RECOVERY; + if (this.ignoreMethodBodies) flags |= ICompilationUnit.IGNORE_METHOD_BODIES; + if (this.resolveBindings) { + if (this.project == null) + throw new IllegalStateException("project not specified"); //$NON-NLS-1$ + if (this.bindingsRecovery) flags |= ICompilationUnit.ENABLE_BINDINGS_RECOVERY; + CompilationUnitResolver.resolve(compilationUnits, bindingKeys, requestor, this.apiLevel, this.compilerOptions, this.project, this.workingCopyOwner, flags, monitor); + } else { + CompilationUnitResolver.parse(compilationUnits, requestor, this.apiLevel, this.compilerOptions, flags, monitor); + } + } finally { + // re-init defaults to allow reuse (and avoid leaking) + initializeDefaults(); + } + } + + /** + * Creates bindings for a batch of Java elements. These elements are either + * enclosed in {@link ICompilationUnit}s or in {@link IClassFile}s. + * <p> + * All enclosing compilation units and class files must + * come from the same Java project, which must be set beforehand + * with <code>setProject</code>. + * </p> + * <p> + * All elements must exist. If one doesn't exist, an <code>IllegalStateException</code> + * is thrown. + * </p> + * <p> + * The returned array has the same size as the given elements array. At a given position + * it contains the binding of the corresponding Java element, or <code>null</code> + * if no binding could be created. + * </p> + * <p> + * Note also the following parser parameters are used, regardless of what + * may have been specified: + * <ul> + * <li>The {@linkplain #setResolveBindings(boolean) binding resolution flag} is <code>true</code></li> + * <li>The {@linkplain #setKind(int) parser kind} is <code>K_COMPILATION_UNIT</code></li> + * <li>The {@linkplain #setSourceRange(int,int) source range} is <code>(0, -1)</code></li> + * <li>The {@linkplain #setFocalPosition(int) focal position} is not set</li> + * </ul> + * </p> + * <p> + * A successful call to this method returns all settings to their + * default values so the object is ready to be reused. + * </p> + * + * @param elements the Java elements to create bindings for + * @return the bindings for the given Java elements, possibly containing <code>null</code>s + * if some bindings could not be created + * @exception IllegalStateException if the settings provided + * are insufficient, contradictory, or otherwise unsupported + * @since 3.1 + */ + public IBinding[] createBindings(IJavaElement[] elements, IProgressMonitor monitor) { + try { + if (this.project == null) + throw new IllegalStateException("project not specified"); //$NON-NLS-1$ + int flags = 0; + if (this.statementsRecovery) flags |= ICompilationUnit.ENABLE_STATEMENTS_RECOVERY; + if (this.bindingsRecovery) flags |= ICompilationUnit.ENABLE_BINDINGS_RECOVERY; + if (this.ignoreMethodBodies) flags |= ICompilationUnit.IGNORE_METHOD_BODIES; + return CompilationUnitResolver.resolve(elements, this.apiLevel, this.compilerOptions, this.project, this.workingCopyOwner, flags, monitor); + } finally { + // re-init defaults to allow reuse (and avoid leaking) + initializeDefaults(); + } + } + + private ASTNode internalCreateAST(IProgressMonitor monitor) { + boolean needToResolveBindings = this.resolveBindings; + switch(this.astKind) { + case K_CLASS_BODY_DECLARATIONS : + case K_EXPRESSION : + case K_STATEMENTS : + if (this.rawSource == null) { + if (this.typeRoot != null) { + // get the source from the type root + if (this.typeRoot instanceof ICompilationUnit) { + org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit = (org.eclipse.jdt.internal.compiler.env.ICompilationUnit) this.typeRoot; + this.rawSource = sourceUnit.getContents(); + } else if (this.typeRoot instanceof IClassFile) { + try { + String sourceString = this.typeRoot.getSource(); + if (sourceString != null) { + this.rawSource = sourceString.toCharArray(); + } + } catch(JavaModelException e) { + // an error occured accessing the java element + StringWriter stringWriter = new StringWriter(); + PrintWriter writer = null; + try { + writer = new PrintWriter(stringWriter); + e.printStackTrace(writer); + } finally { + if (writer != null) writer.close(); + } + throw new IllegalStateException(String.valueOf(stringWriter.getBuffer())); + } + } + } + } + if (this.rawSource != null) { + if (this.sourceOffset + this.sourceLength > this.rawSource.length) { + throw new IllegalStateException(); + } + return internalCreateASTForKind(); + } + break; + case K_COMPILATION_UNIT : + CompilationUnitDeclaration compilationUnitDeclaration = null; + try { + NodeSearcher searcher = null; + org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit = null; + WorkingCopyOwner wcOwner = this.workingCopyOwner; + if (this.typeRoot instanceof ICompilationUnit) { + /* + * this.compilationUnitSource is an instance of org.eclipse.jdt.internal.core.CompilationUnit that implements + * both org.eclipse.jdt.core.ICompilationUnit and org.eclipse.jdt.internal.compiler.env.ICompilationUnit + */ + sourceUnit = (org.eclipse.jdt.internal.compiler.env.ICompilationUnit) this.typeRoot; + /* + * use a BasicCompilation that caches the source instead of using the compilationUnitSource directly + * (if it is a working copy, the source can change between the parse and the AST convertion) + * (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=75632) + */ + sourceUnit = new BasicCompilationUnit(sourceUnit.getContents(), sourceUnit.getPackageName(), new String(sourceUnit.getFileName()), this.project); + wcOwner = ((ICompilationUnit) this.typeRoot).getOwner(); + } else if (this.typeRoot instanceof IClassFile) { + try { + String sourceString = this.typeRoot.getSource(); + if (sourceString == null) { + throw new IllegalStateException(); + } + PackageFragment packageFragment = (PackageFragment) this.typeRoot.getParent(); + BinaryType type = (BinaryType) this.typeRoot.findPrimaryType(); + IBinaryType binaryType = (IBinaryType) type.getElementInfo(); + // file name is used to recreate the Java element, so it has to be the toplevel .class file name + char[] fileName = binaryType.getFileName(); + int firstDollar = CharOperation.indexOf('$', fileName); + if (firstDollar != -1) { + char[] suffix = SuffixConstants.SUFFIX_class; + int suffixLength = suffix.length; + char[] newFileName = new char[firstDollar + suffixLength]; + System.arraycopy(fileName, 0, newFileName, 0, firstDollar); + System.arraycopy(suffix, 0, newFileName, firstDollar, suffixLength); + fileName = newFileName; + } + sourceUnit = new BasicCompilationUnit(sourceString.toCharArray(), Util.toCharArrays(packageFragment.names), new String(fileName), this.project); + } catch(JavaModelException e) { + // an error occured accessing the java element + StringWriter stringWriter = new StringWriter(); + PrintWriter writer = null; + try { + writer = new PrintWriter(stringWriter); + e.printStackTrace(writer); + } finally { + if (writer != null) writer.close(); + } + throw new IllegalStateException(String.valueOf(stringWriter.getBuffer())); + } + } else if (this.rawSource != null) { + needToResolveBindings = this.resolveBindings && this.unitName != null && this.project != null && this.compilerOptions != null; + sourceUnit = new BasicCompilationUnit(this.rawSource, null, this.unitName == null ? "" : this.unitName, this.project); //$NON-NLS-1$ + } else { + throw new IllegalStateException(); + } + if (this.partial) { + searcher = new NodeSearcher(this.focalPointPosition); + } + int flags = 0; + if (this.statementsRecovery) flags |= ICompilationUnit.ENABLE_STATEMENTS_RECOVERY; + if (searcher == null && this.ignoreMethodBodies) flags |= ICompilationUnit.IGNORE_METHOD_BODIES; + if (needToResolveBindings) { + if (this.bindingsRecovery) flags |= ICompilationUnit.ENABLE_BINDINGS_RECOVERY; + try { + // parse and resolve + compilationUnitDeclaration = + CompilationUnitResolver.resolve( + sourceUnit, + this.project, + searcher, + this.compilerOptions, + this.workingCopyOwner, + flags, + monitor); + } catch (JavaModelException e) { + flags &= ~ICompilationUnit.ENABLE_BINDINGS_RECOVERY; + compilationUnitDeclaration = CompilationUnitResolver.parse( + sourceUnit, + searcher, + this.compilerOptions, + flags); + needToResolveBindings = false; +//{ObjectTeams: one more error to catch: + } catch (InternalCompilerError ice) { + flags &= ~ICompilationUnit.ENABLE_BINDINGS_RECOVERY; + compilationUnitDeclaration = CompilationUnitResolver.parse( + sourceUnit, + searcher, + this.compilerOptions, + flags); + needToResolveBindings = false; +// SH} + } + } else { + compilationUnitDeclaration = CompilationUnitResolver.parse( + sourceUnit, + searcher, + this.compilerOptions, + flags); + needToResolveBindings = false; + } + CompilationUnit result = CompilationUnitResolver.convert( + compilationUnitDeclaration, + sourceUnit.getContents(), + this.apiLevel, + this.compilerOptions, + needToResolveBindings, + wcOwner, + needToResolveBindings ? new DefaultBindingResolver.BindingTables() : null, + flags, + monitor); + result.setTypeRoot(this.typeRoot); + return result; + } finally { + if (compilationUnitDeclaration != null && this.resolveBindings) { + compilationUnitDeclaration.cleanUp(); + } + } + } + throw new IllegalStateException(); + } + + /** + * Parses the given source between the bounds specified by the given offset (inclusive) + * and the given length and creates and returns a corresponding abstract syntax tree. + * <p> + * When the parse is successful the result returned includes the ASTs for the + * requested source: + * <ul> + * <li>{@link #K_CLASS_BODY_DECLARATIONS K_CLASS_BODY_DECLARATIONS}: The result node + * is a {@link TypeDeclaration TypeDeclaration} whose + * {@link TypeDeclaration#bodyDeclarations() bodyDeclarations} + * are the new trees. Other aspects of the type declaration are unspecified.</li> + * <li>{@link #K_STATEMENTS K_STATEMENTS}: The result node is a + * {@link Block Block} whose {@link Block#statements() statements} + * are the new trees. Other aspects of the block are unspecified.</li> + * <li>{@link #K_EXPRESSION K_EXPRESSION}: The result node is a subclass of + * {@link Expression Expression}. Other aspects of the expression are unspecified.</li> + * </ul> + * The resulting AST node is rooted under an contrived + * {@link CompilationUnit CompilationUnit} node, to allow the + * client to retrieve the following pieces of information + * available there: + * <ul> + * <li>{@linkplain CompilationUnit#getLineNumber(int) Line number map}. Line + * numbers start at 1 and only cover the subrange scanned + * (<code>source[offset]</code> through <code>source[offset+length-1]</code>).</li> + * <li>{@linkplain CompilationUnit#getMessages() Compiler messages} + * and {@linkplain CompilationUnit#getProblems() detailed problem reports}. + * Character positions are relative to the start of + * <code>source</code>; line positions are for the subrange scanned.</li> + * <li>{@linkplain CompilationUnit#getCommentList() Comment list} + * for the subrange scanned.</li> + * </ul> + * The contrived nodes do not have source positions. Other aspects of the + * {@link CompilationUnit CompilationUnit} node are unspecified, including + * the exact arrangment of intervening nodes. + * </p> + * <p> + * Lexical or syntax errors detected while parsing can result in + * a result node being marked as {@link ASTNode#MALFORMED MALFORMED}. + * In more severe failure cases where the parser is unable to + * recognize the input, this method returns + * a {@link CompilationUnit CompilationUnit} node with at least the + * compiler messages. + * </p> + * <p>Each node in the subtree (other than the contrived nodes) + * carries source range(s) information relating back + * to positions in the given source (the given source itself + * is not remembered with the AST). + * The source range usually begins at the first character of the first token + * corresponding to the node; leading whitespace and comments are <b>not</b> + * included. The source range usually extends through the last character of + * the last token corresponding to the node; trailing whitespace and + * comments are <b>not</b> included. There are a handful of exceptions + * (including the various body declarations); the + * specification for these node type spells out the details. + * Source ranges nest properly: the source range for a child is always + * within the source range of its parent, and the source ranges of sibling + * nodes never overlap. + * </p> + * <p> + * This method does not compute binding information; all <code>resolveBinding</code> + * methods applied to nodes of the resulting AST return <code>null</code>. + * </p> + * + * @return an AST node whose type depends on the kind of parse + * requested, with a fallback to a <code>CompilationUnit</code> + * in the case of severe parsing errors + * @see ASTNode#getStartPosition() + * @see ASTNode#getLength() + */ + private ASTNode internalCreateASTForKind() { + final ASTConverter converter = new ASTConverter(this.compilerOptions, false, null); + converter.compilationUnitSource = this.rawSource; + converter.compilationUnitSourceLength = this.rawSource.length; + converter.scanner.setSource(this.rawSource); + + AST ast = AST.newAST(this.apiLevel); + ast.setDefaultNodeFlag(ASTNode.ORIGINAL); + ast.setBindingResolver(new BindingResolver()); + if (this.statementsRecovery) { + ast.setFlag(ICompilationUnit.ENABLE_STATEMENTS_RECOVERY); + } + converter.setAST(ast); + CodeSnippetParsingUtil codeSnippetParsingUtil = new CodeSnippetParsingUtil(this.ignoreMethodBodies); + CompilationUnit compilationUnit = ast.newCompilationUnit(); + if (this.sourceLength == -1) { + this.sourceLength = this.rawSource.length; + } + switch(this.astKind) { + case K_STATEMENTS : + ConstructorDeclaration constructorDeclaration = codeSnippetParsingUtil.parseStatements(this.rawSource, this.sourceOffset, this.sourceLength, this.compilerOptions, true, this.statementsRecovery); + RecoveryScannerData data = constructorDeclaration.compilationResult.recoveryScannerData; + if(data != null) { + Scanner scanner = converter.scanner; + converter.scanner = new RecoveryScanner(scanner, data.removeUnused()); + converter.docParser.scanner = converter.scanner; + converter.scanner.setSource(scanner.source); + + compilationUnit.setStatementsRecoveryData(data); + } + RecordedParsingInformation recordedParsingInformation = codeSnippetParsingUtil.recordedParsingInformation; + int[][] comments = recordedParsingInformation.commentPositions; + if (comments != null) { + converter.buildCommentsTable(compilationUnit, comments); + } + compilationUnit.setLineEndTable(recordedParsingInformation.lineEnds); + Block block = ast.newBlock(); + block.setSourceRange(this.sourceOffset, this.sourceOffset + this.sourceLength); + org.eclipse.jdt.internal.compiler.ast.Statement[] statements = constructorDeclaration.statements; + if (statements != null) { + int statementsLength = statements.length; + for (int i = 0; i < statementsLength; i++) { + if (statements[i] instanceof org.eclipse.jdt.internal.compiler.ast.LocalDeclaration) { + converter.checkAndAddMultipleLocalDeclaration(statements, i, block.statements()); + } else { + Statement statement = converter.convert(statements[i]); + if (statement != null) { + block.statements().add(statement); + } + } + } + } + rootNodeToCompilationUnit(ast, compilationUnit, block, recordedParsingInformation, data); + ast.setDefaultNodeFlag(0); + ast.setOriginalModificationCount(ast.modificationCount()); + return block; + case K_EXPRESSION : + org.eclipse.jdt.internal.compiler.ast.Expression expression = codeSnippetParsingUtil.parseExpression(this.rawSource, this.sourceOffset, this.sourceLength, this.compilerOptions, true); + recordedParsingInformation = codeSnippetParsingUtil.recordedParsingInformation; + comments = recordedParsingInformation.commentPositions; + if (comments != null) { + converter.buildCommentsTable(compilationUnit, comments); + } + compilationUnit.setLineEndTable(recordedParsingInformation.lineEnds); + if (expression != null) { + Expression expression2 = converter.convert(expression); + rootNodeToCompilationUnit(expression2.getAST(), compilationUnit, expression2, codeSnippetParsingUtil.recordedParsingInformation, null); + ast.setDefaultNodeFlag(0); + ast.setOriginalModificationCount(ast.modificationCount()); + return expression2; + } else { + CategorizedProblem[] problems = recordedParsingInformation.problems; + if (problems != null) { + compilationUnit.setProblems(problems); + } + ast.setDefaultNodeFlag(0); + ast.setOriginalModificationCount(ast.modificationCount()); + return compilationUnit; + } + case K_CLASS_BODY_DECLARATIONS : + final org.eclipse.jdt.internal.compiler.ast.ASTNode[] nodes = codeSnippetParsingUtil.parseClassBodyDeclarations(this.rawSource, this.sourceOffset, this.sourceLength, this.compilerOptions, true, this.statementsRecovery); + recordedParsingInformation = codeSnippetParsingUtil.recordedParsingInformation; + comments = recordedParsingInformation.commentPositions; + if (comments != null) { + converter.buildCommentsTable(compilationUnit, comments); + } + compilationUnit.setLineEndTable(recordedParsingInformation.lineEnds); + if (nodes != null) { + // source has no syntax error or the statement recovery is enabled + TypeDeclaration typeDeclaration = converter.convert(nodes); + typeDeclaration.setSourceRange(this.sourceOffset, this.sourceOffset + this.sourceLength); + rootNodeToCompilationUnit(typeDeclaration.getAST(), compilationUnit, typeDeclaration, codeSnippetParsingUtil.recordedParsingInformation, null); + ast.setDefaultNodeFlag(0); + ast.setOriginalModificationCount(ast.modificationCount()); + return typeDeclaration; + } else { + // source has syntax error and the statement recovery is disabled + CategorizedProblem[] problems = recordedParsingInformation.problems; + if (problems != null) { + compilationUnit.setProblems(problems); + } + ast.setDefaultNodeFlag(0); + ast.setOriginalModificationCount(ast.modificationCount()); + return compilationUnit; + } + } + throw new IllegalStateException(); + } + + private void propagateErrors(ASTNode astNode, CategorizedProblem[] problems, RecoveryScannerData data) { + astNode.accept(new ASTSyntaxErrorPropagator(problems)); + if (data != null) { + astNode.accept(new ASTRecoveryPropagator(problems, data)); + } + } + + private void rootNodeToCompilationUnit(AST ast, CompilationUnit compilationUnit, ASTNode node, RecordedParsingInformation recordedParsingInformation, RecoveryScannerData data) { + final int problemsCount = recordedParsingInformation.problemsCount; + switch(node.getNodeType()) { + case ASTNode.BLOCK : + { + Block block = (Block) node; + if (problemsCount != 0) { + // propagate and record problems + final CategorizedProblem[] problems = recordedParsingInformation.problems; + propagateErrors(block, problems, data); + compilationUnit.setProblems(problems); + } + TypeDeclaration typeDeclaration = ast.newTypeDeclaration(); + Initializer initializer = ast.newInitializer(); + initializer.setBody(block); + typeDeclaration.bodyDeclarations().add(initializer); + compilationUnit.types().add(typeDeclaration); + } + break; + case ASTNode.TYPE_DECLARATION : + { + TypeDeclaration typeDeclaration = (TypeDeclaration) node; + if (problemsCount != 0) { + // propagate and record problems + final CategorizedProblem[] problems = recordedParsingInformation.problems; + propagateErrors(typeDeclaration, problems, data); + compilationUnit.setProblems(problems); + } + compilationUnit.types().add(typeDeclaration); + } + break; + default : + if (node instanceof Expression) { + Expression expression = (Expression) node; + if (problemsCount != 0) { + // propagate and record problems + final CategorizedProblem[] problems = recordedParsingInformation.problems; + propagateErrors(expression, problems, data); + compilationUnit.setProblems(problems); + } + ExpressionStatement expressionStatement = ast.newExpressionStatement(expression); + Block block = ast.newBlock(); + block.statements().add(expressionStatement); + Initializer initializer = ast.newInitializer(); + initializer.setBody(block); + TypeDeclaration typeDeclaration = ast.newTypeDeclaration(); + typeDeclaration.bodyDeclarations().add(initializer); + compilationUnit.types().add(typeDeclaration); + } + } + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTRecoveryPropagator.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTRecoveryPropagator.java new file mode 100644 index 000000000..641356c05 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTRecoveryPropagator.java @@ -0,0 +1,449 @@ +/******************************************************************************* + * Copyright (c) 2006, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.List; +import java.util.Vector; + +import org.eclipse.jdt.core.compiler.CategorizedProblem; +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.core.compiler.IProblem; +import org.eclipse.jdt.internal.compiler.parser.RecoveryScanner; +import org.eclipse.jdt.internal.compiler.parser.RecoveryScannerData; +import org.eclipse.jdt.internal.compiler.parser.TerminalTokens; +import org.eclipse.jdt.internal.compiler.util.HashtableOfObjectToIntArray; + +/** + * Internal AST visitor for propagating syntax errors. + */ +class ASTRecoveryPropagator extends DefaultASTVisitor { + private static final int NOTHING = -1; + HashtableOfObjectToIntArray endingTokens = new HashtableOfObjectToIntArray(); + { + this.endingTokens.put(AnonymousClassDeclaration.class, new int[]{TerminalTokens.TokenNameRBRACE}); + this.endingTokens.put(ArrayAccess.class, new int[]{TerminalTokens.TokenNameRBRACKET}); + this.endingTokens.put(ArrayCreation.class, new int[]{NOTHING, TerminalTokens.TokenNameRBRACKET}); + this.endingTokens.put(ArrayInitializer.class, new int[]{TerminalTokens.TokenNameRBRACE}); + this.endingTokens.put(ArrayType.class, new int[]{TerminalTokens.TokenNameRBRACKET}); + this.endingTokens.put(AssertStatement.class, new int[]{TerminalTokens.TokenNameSEMICOLON}); + this.endingTokens.put(Block.class, new int[]{TerminalTokens.TokenNameRBRACE}); + this.endingTokens.put(BooleanLiteral.class, new int[]{TerminalTokens.TokenNamefalse, TerminalTokens.TokenNametrue}); + this.endingTokens.put(BreakStatement.class, new int[]{TerminalTokens.TokenNameSEMICOLON}); + this.endingTokens.put(CharacterLiteral.class, new int[]{TerminalTokens.TokenNameCharacterLiteral}); + this.endingTokens.put(ClassInstanceCreation.class, new int[]{TerminalTokens.TokenNameRBRACE, TerminalTokens.TokenNameRPAREN}); + this.endingTokens.put(ConstructorInvocation.class, new int[]{TerminalTokens.TokenNameSEMICOLON}); + this.endingTokens.put(ContinueStatement.class, new int[]{TerminalTokens.TokenNameSEMICOLON}); + this.endingTokens.put(DoStatement.class, new int[]{TerminalTokens.TokenNameRPAREN}); + this.endingTokens.put(EmptyStatement.class, new int[]{TerminalTokens.TokenNameSEMICOLON}); + this.endingTokens.put(ExpressionStatement.class, new int[]{TerminalTokens.TokenNameSEMICOLON}); + this.endingTokens.put(FieldDeclaration.class, new int[]{TerminalTokens.TokenNameSEMICOLON}); + this.endingTokens.put(ImportDeclaration.class, new int[]{TerminalTokens.TokenNameSEMICOLON}); + this.endingTokens.put(Initializer.class, new int[]{TerminalTokens.TokenNameRBRACE}); + this.endingTokens.put(MethodDeclaration.class, new int[]{NOTHING, TerminalTokens.TokenNameSEMICOLON}); + this.endingTokens.put(MethodInvocation.class, new int[]{TerminalTokens.TokenNameRPAREN}); + this.endingTokens.put(NullLiteral.class, new int[]{TerminalTokens.TokenNamenull}); + this.endingTokens.put(NumberLiteral.class, new int[]{TerminalTokens.TokenNameIntegerLiteral, TerminalTokens.TokenNameLongLiteral, TerminalTokens.TokenNameFloatingPointLiteral, TerminalTokens.TokenNameDoubleLiteral}); + this.endingTokens.put(PackageDeclaration.class, new int[]{TerminalTokens.TokenNameSEMICOLON}); + this.endingTokens.put(ParenthesizedExpression.class, new int[]{TerminalTokens.TokenNameRPAREN}); + this.endingTokens.put(PostfixExpression.class, new int[]{TerminalTokens.TokenNamePLUS_PLUS, TerminalTokens.TokenNameMINUS_MINUS}); + this.endingTokens.put(PrimitiveType.class, new int[]{TerminalTokens.TokenNamebyte, TerminalTokens.TokenNameshort, TerminalTokens.TokenNamechar, TerminalTokens.TokenNameint, TerminalTokens.TokenNamelong, TerminalTokens.TokenNamefloat, TerminalTokens.TokenNameboolean, TerminalTokens.TokenNamedouble, TerminalTokens.TokenNamevoid}); + this.endingTokens.put(ReturnStatement.class, new int[]{TerminalTokens.TokenNameSEMICOLON}); + this.endingTokens.put(SimpleName.class, new int[]{TerminalTokens.TokenNameIdentifier}); + this.endingTokens.put(SingleVariableDeclaration.class, new int[]{TerminalTokens.TokenNameSEMICOLON}); + this.endingTokens.put(StringLiteral.class, new int[]{TerminalTokens.TokenNameStringLiteral}); + this.endingTokens.put(SuperConstructorInvocation.class, new int[]{TerminalTokens.TokenNameSEMICOLON}); + this.endingTokens.put(SuperMethodInvocation.class, new int[]{TerminalTokens.TokenNameRPAREN}); + this.endingTokens.put(SwitchCase.class, new int[]{TerminalTokens.TokenNameCOLON}); + this.endingTokens.put(SwitchStatement.class, new int[]{TerminalTokens.TokenNameRBRACE}); + this.endingTokens.put(SynchronizedStatement.class, new int[]{TerminalTokens.TokenNameRBRACE}); + this.endingTokens.put(ThisExpression.class, new int[]{TerminalTokens.TokenNamethis}); + this.endingTokens.put(ThrowStatement.class, new int[]{TerminalTokens.TokenNameSEMICOLON}); + this.endingTokens.put(TypeDeclaration.class, new int[]{TerminalTokens.TokenNameRBRACE}); + this.endingTokens.put(TypeLiteral.class, new int[]{TerminalTokens.TokenNameclass}); + this.endingTokens.put(VariableDeclarationStatement.class, new int[]{TerminalTokens.TokenNameSEMICOLON}); + } + + private CategorizedProblem[] problems; + private boolean[] usedOrIrrelevantProblems; + + private RecoveryScannerData data; + private int blockDepth = 0; + private int lastEnd; + + private int[] insertedTokensKind; + private int[] insertedTokensPosition; + private boolean[] insertedTokensFlagged; + + private boolean[] removedTokensFlagged; + private boolean[] replacedTokensFlagged; + + private Vector stack = new Vector(); + + /** + * @noreference This method is not intended to be referenced by clients. + */ + ASTRecoveryPropagator(CategorizedProblem[] problems, RecoveryScannerData data) { + // visit Javadoc.tags() as well + this.problems = problems; + this.usedOrIrrelevantProblems = new boolean[problems.length]; + + this.data = data; + + if(this.data != null) { + + int length = 0; + for (int i = 0; i < data.insertedTokensPtr + 1; i++) { + length += data.insertedTokens[i].length; + } + this.insertedTokensKind = new int[length]; + this.insertedTokensPosition = new int[length]; + this.insertedTokensFlagged = new boolean[length]; + int tokenCount = 0; + for (int i = 0; i < data.insertedTokensPtr + 1; i++) { + for (int j = 0; j < data.insertedTokens[i].length; j++) { + this.insertedTokensKind[tokenCount] = data.insertedTokens[i][j]; + this.insertedTokensPosition[tokenCount] = data.insertedTokensPosition[i]; + tokenCount++; + } + } + + if(data.removedTokensPtr != -1) { + this.removedTokensFlagged = new boolean[data.removedTokensPtr + 1]; + } + if(data.replacedTokensPtr != -1) { + this.replacedTokensFlagged = new boolean[data.replacedTokensPtr + 1]; + } + } + } + + public void endVisit(Block node) { + this.blockDepth--; + if(this.blockDepth <= 0) { + flagNodeWithInsertedTokens(); + } + super.endVisit(node); + } + + + + public boolean visit(Block node) { + boolean visitChildren = super.visit(node); + this.blockDepth++; + return visitChildren; + } + + protected boolean visitNode(ASTNode node) { + if(this.blockDepth > 0) { + int start = node.getStartPosition(); + int end = start + node.getLength() - 1; + + // continue to visit the node only if it contains tokens modifications + + if(this.insertedTokensFlagged != null) { + for (int i = 0; i < this.insertedTokensFlagged.length; i++) { + if(this.insertedTokensPosition[i] >= start && + this.insertedTokensPosition[i] <= end) { + return true; + } + } + } + + if(this.removedTokensFlagged != null) { + for (int i = 0; i <= this.data.removedTokensPtr; i++) { + if(this.data.removedTokensStart[i] >= start && + this.data.removedTokensEnd[i] <= end) { + return true; + } + } + } + + if(this.replacedTokensFlagged != null) { + for (int i = 0; i <= this.data.replacedTokensPtr; i++) { + if(this.data.replacedTokensStart[i] >= start && + this.data.replacedTokensEnd[i] <= end) { + return true; + } + } + } + + return false; + } + return true; + } + + protected void endVisitNode(ASTNode node) { + int start = node.getStartPosition(); + int end = start + node.getLength() - 1; + + // is inside diet part of the ast + if(this.blockDepth < 1) { + switch (node.getNodeType()) { + case ASTNode.ANNOTATION_TYPE_DECLARATION: + case ASTNode.COMPILATION_UNIT: + case ASTNode.ENUM_DECLARATION: + case ASTNode.FIELD_DECLARATION: + case ASTNode.IMPORT_DECLARATION: + case ASTNode.INITIALIZER: + case ASTNode.METHOD_DECLARATION: + case ASTNode.PACKAGE_DECLARATION: + case ASTNode.TYPE_DECLARATION: + case ASTNode.MARKER_ANNOTATION: + case ASTNode.NORMAL_ANNOTATION: + case ASTNode.SINGLE_MEMBER_ANNOTATION: + case ASTNode.BLOCK: + if(markIncludedProblems(start, end)) { + node.setFlags(node.getFlags() | ASTNode.RECOVERED); + } + break; + } + } else { + markIncludedProblems(start, end); + + if(this.insertedTokensFlagged != null) { + if(this.lastEnd != end) { + flagNodeWithInsertedTokens(); + } + this.stack.add(node); + } + + if(this.removedTokensFlagged != null) { + for (int i = 0; i <= this.data.removedTokensPtr; i++) { + if(!this.removedTokensFlagged[i] && + this.data.removedTokensStart[i] >= start && + this.data.removedTokensEnd[i] <= end) { + node.setFlags(node.getFlags() | ASTNode.RECOVERED); + this.removedTokensFlagged[i] = true; + } + } + } + + if(this.replacedTokensFlagged != null) { + for (int i = 0; i <= this.data.replacedTokensPtr; i++) { + if(!this.replacedTokensFlagged[i] && + this.data.replacedTokensStart[i] >= start && + this.data.replacedTokensEnd[i] <= end) { + node.setFlags(node.getFlags() | ASTNode.RECOVERED); + this.replacedTokensFlagged[i] = true; + } + } + } + } + this.lastEnd = end; + } + + private void flagNodeWithInsertedTokens() { + if(this.insertedTokensKind != null && this.insertedTokensKind.length > 0) { + int s = this.stack.size(); + for (int i = s - 1; i > -1; i--) { + flagNodesWithInsertedTokensAtEnd((ASTNode)this.stack.get(i)); + } + for (int i = 0; i < s; i++) { + flagNodesWithInsertedTokensInside((ASTNode)this.stack.get(i)); + } + this.stack = new Vector(); + } + } + + private boolean flagNodesWithInsertedTokensAtEnd(ASTNode node) { + int[] expectedEndingToken = this.endingTokens.get(node.getClass()); + if (expectedEndingToken != null) { + int start = node.getStartPosition(); + int end = start + node.getLength() - 1; + + boolean flagParent = false; + done : for (int i = this.insertedTokensKind.length - 1; i > -1 ; i--) { + if(!this.insertedTokensFlagged[i] && + this.insertedTokensPosition[i] == end){ + this.insertedTokensFlagged[i] = true; + for (int j = 0; j < expectedEndingToken.length; j++) { + if(expectedEndingToken[j] == this.insertedTokensKind[i]) { + node.setFlags(node.getFlags() | ASTNode.RECOVERED); + break done; + } + } + flagParent = true; + } + } + + if(flagParent) { + ASTNode parent = node.getParent(); + while (parent != null) { + parent.setFlags(node.getFlags() | ASTNode.RECOVERED); + if((parent.getStartPosition() + parent.getLength() - 1) != end) { + parent = null; + } else { + parent = parent.getParent(); + } + } + } + } + return true; + } + + private boolean flagNodesWithInsertedTokensInside(ASTNode node) { + int start = node.getStartPosition(); + int end = start + node.getLength() - 1; + for (int i = 0; i < this.insertedTokensKind.length; i++) { + if(!this.insertedTokensFlagged[i] && + start <= this.insertedTokensPosition[i] && + this.insertedTokensPosition[i] < end){ + node.setFlags(node.getFlags() | ASTNode.RECOVERED); + this.insertedTokensFlagged[i] = true; + } + } + return true; + } + + private boolean markIncludedProblems(int start, int end) { + boolean foundProblems = false; + next: for (int i = 0, max = this.problems.length; i < max; i++) { + CategorizedProblem problem = this.problems[i]; + + if(this.usedOrIrrelevantProblems[i]) continue next; + + switch(problem.getID()) { + case IProblem.ParsingErrorOnKeywordNoSuggestion : + case IProblem.ParsingErrorOnKeyword : + case IProblem.ParsingError : + case IProblem.ParsingErrorNoSuggestion : + case IProblem.ParsingErrorInsertTokenBefore : + case IProblem.ParsingErrorInsertTokenAfter : + case IProblem.ParsingErrorDeleteToken : + case IProblem.ParsingErrorDeleteTokens : + case IProblem.ParsingErrorMergeTokens : + case IProblem.ParsingErrorInvalidToken : + case IProblem.ParsingErrorMisplacedConstruct : + case IProblem.ParsingErrorReplaceTokens : + case IProblem.ParsingErrorNoSuggestionForTokens : + case IProblem.ParsingErrorUnexpectedEOF : + case IProblem.ParsingErrorInsertToComplete : + case IProblem.ParsingErrorInsertToCompleteScope : + case IProblem.ParsingErrorInsertToCompletePhrase : + case IProblem.EndOfSource : + case IProblem.InvalidHexa : + case IProblem.InvalidOctal : + case IProblem.InvalidCharacterConstant : + case IProblem.InvalidEscape : + case IProblem.InvalidInput : + case IProblem.InvalidUnicodeEscape : + case IProblem.InvalidFloat : + case IProblem.NullSourceString : + case IProblem.UnterminatedString : + case IProblem.UnterminatedComment : + case IProblem.InvalidDigit : + break; + default: + this.usedOrIrrelevantProblems[i] = true; + continue next; + + } + + int problemStart = problem.getSourceStart(); + int problemEnd = problem.getSourceEnd(); + if ((start <= problemStart) && (problemStart <= end) || + (start <= problemEnd) && (problemEnd <= end)) { + this.usedOrIrrelevantProblems[i] = true; + foundProblems = true; + } + } + return foundProblems; + } + + public void endVisit(ExpressionStatement node) { + endVisitNode(node); + if ((node.getFlags() & ASTNode.RECOVERED) == 0) return; + Expression expression = node.getExpression(); + if (expression.getNodeType() == ASTNode.ASSIGNMENT) { + Assignment assignment = (Assignment) expression; + Expression rightHandSide = assignment.getRightHandSide(); + if (rightHandSide.getNodeType() == ASTNode.SIMPLE_NAME) { + SimpleName simpleName = (SimpleName) rightHandSide; + if (CharOperation.equals(RecoveryScanner.FAKE_IDENTIFIER, simpleName.getIdentifier().toCharArray())) { + Expression expression2 = assignment.getLeftHandSide(); + // unparent the expression to add it in the expression stateemnt + expression2.setParent(null, null); + expression2.setFlags(expression2.getFlags() | ASTNode.RECOVERED); + node.setExpression(expression2); + } + } + } + } + + public void endVisit(ForStatement node) { + endVisitNode(node); + List initializers = node.initializers(); + if (initializers.size() == 1) { + Expression expression = (Expression) initializers.get(0); + if (expression.getNodeType() == ASTNode.VARIABLE_DECLARATION_EXPRESSION) { + VariableDeclarationExpression variableDeclarationExpression = (VariableDeclarationExpression) expression; + List fragments = variableDeclarationExpression.fragments(); + for (int i = 0, max = fragments.size(); i <max; i++) { + VariableDeclarationFragment fragment = (VariableDeclarationFragment) fragments.get(i); + SimpleName simpleName = fragment.getName(); + if (CharOperation.equals(RecoveryScanner.FAKE_IDENTIFIER, simpleName.getIdentifier().toCharArray())) { + fragments.remove(fragment); + variableDeclarationExpression.setFlags(variableDeclarationExpression.getFlags() | ASTNode.RECOVERED); + } + } + } + } + } + + public void endVisit(VariableDeclarationStatement node) { + endVisitNode(node); + List fragments = node.fragments(); + for (int i = 0, max = fragments.size(); i <max; i++) { + VariableDeclarationFragment fragment = (VariableDeclarationFragment) fragments.get(i); + Expression expression = fragment.getInitializer(); + if (expression == null) continue; + if ((expression.getFlags() & ASTNode.RECOVERED) == 0) continue; + if (expression.getNodeType() == ASTNode.SIMPLE_NAME) { + SimpleName simpleName = (SimpleName) expression; + if (CharOperation.equals(RecoveryScanner.FAKE_IDENTIFIER, simpleName.getIdentifier().toCharArray())) { + fragment.setInitializer(null); + fragment.setFlags(fragment.getFlags() | ASTNode.RECOVERED); + } + } + } + } + + public void endVisit(NormalAnnotation node) { + endVisitNode(node); + // is inside diet part of the ast + if(this.blockDepth < 1) { + List values = node.values(); + int size = values.size(); + if (size > 0) { + MemberValuePair lastMemberValuePair = (MemberValuePair)values.get(size - 1); + + int annotationEnd = node.getStartPosition() + node.getLength(); + int lastMemberValuePairEnd = lastMemberValuePair.getStartPosition() + lastMemberValuePair.getLength(); + if (annotationEnd == lastMemberValuePairEnd) { + node.setFlags(node.getFlags() | ASTNode.RECOVERED); + } + } + } + } + + public void endVisit(SingleMemberAnnotation node) { + endVisitNode(node); + // is inside diet part of the ast + if(this.blockDepth < 1) { + Expression value = node.getValue(); + int annotationEnd = node.getStartPosition() + node.getLength(); + int valueEnd = value.getStartPosition() + value.getLength(); + if (annotationEnd == valueEnd) { + node.setFlags(node.getFlags() | ASTNode.RECOVERED); + } + } + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTRequestor.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTRequestor.java new file mode 100644 index 000000000..e493b1586 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTRequestor.java @@ -0,0 +1,118 @@ +/******************************************************************************* + * Copyright (c) 2005, 2009 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.dom; + +import org.eclipse.jdt.core.ICompilationUnit; + +/** + * An AST requestor handles ASTs for compilation units passed to + * <code>ASTParser.createASTs</code>. + * <p> + * <code>ASTRequestor.acceptAST</code> is called for each of the + * compilation units passed to <code>ASTParser.createASTs</code>. + * After all the compilation units have been processed, + * <code>ASTRequestor.acceptBindings</code> is called for each + * of the binding keys passed to <code>ASTParser.createASTs</code>. + * </p> + * <p> + * This class is intended to be subclassed by clients. + * AST requestors are serially reusable, but neither reentrant nor + * thread-safe. + * </p> + * + * @see ASTParser#createASTs(ICompilationUnit[], String[], ASTRequestor, org.eclipse.core.runtime.IProgressMonitor) + * @since 3.1 + */ +public abstract class ASTRequestor { + + /** + * The compilation unit resolver used to resolve bindings, or + * <code>null</code> if none. Note that this field is non-null + * only within the dynamic scope of a call to + * <code>ASTParser.createASTs</code>. + */ + CompilationUnitResolver compilationUnitResolver = null; + + /** + * Creates a new instance. + */ + protected ASTRequestor() { + // do nothing + } + + /** + * Accepts an AST corresponding to the compilation unit. + * That is, <code>ast</code> is an AST for <code>source</code>. + * <p> + * The default implementation of this method does nothing. + * Clients should override to process the resulting AST. + * </p> + * + * @param source the compilation unit the ast is coming from + * @param ast the requested abtract syntax tree + */ + public void acceptAST(ICompilationUnit source, CompilationUnit ast) { + // do nothing + } + + /** + * Accepts a binding corresponding to the binding key. + * That is, <code>binding</code> is the binding for + * <code>bindingKey</code>; <code>binding</code> is <code>null</code> + * if the key cannot be resolved. + * <p> + * The default implementation of this method does nothing. + * Clients should override to process the resulting binding. + * </p> + * + * @param bindingKey the key of the requested binding + * @param binding the requested binding, or <code>null</code> if none + */ + public void acceptBinding(String bindingKey, IBinding binding) { + // do nothing + } + + /** + * Resolves bindings for the given binding keys. + * The given binding keys must have been obtained earlier + * using {@link IBinding#getKey()}. + * <p> + * If a binding key cannot be resolved, <code>null</code> is put in the resulting array. + * Bindings can only be resolved in the dynamic scope of a <code>ASTParser.createASTs</code>, + * and only if <code>ASTParser.resolveBindings(true)</code> was specified. + * </p> + * <p> + * Caveat: During an <code>acceptAST</code> callback, there are implementation + * limitations concerning the look up of binding keys representing local elements. + * In some cases, the binding is unavailable, and <code>null</code> will be returned. + * This is only an issue during an <code>acceptAST</code> callback, and only + * when the binding key represents a local element (e.g., local variable, + * local class, method declared in anonymous class). There is no such limitation + * outside of <code>acceptAST</code> callbacks, or for top-level types and their + * members even within <code>acceptAST</code> callbacks. + * </p> + * + * @param bindingKeys the binding keys to look up + * @return a list of bindings paralleling the <code>bindingKeys</code> parameter, + * with <code>null</code> entries for keys that could not be resolved + */ + public final IBinding[] createBindings(String[] bindingKeys) { + int length = bindingKeys.length; + IBinding[] result = new IBinding[length]; + for (int i = 0; i < length; i++) { + result[i] = null; + if (this.compilationUnitResolver != null) { + result[i] = this.compilationUnitResolver.createBinding(bindingKeys[i]); + } + } + return result; + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTSyntaxErrorPropagator.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTSyntaxErrorPropagator.java new file mode 100644 index 000000000..437d9c197 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTSyntaxErrorPropagator.java @@ -0,0 +1,148 @@ +/******************************************************************************* + * Copyright (c) 2000, 2009 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import org.eclipse.jdt.core.compiler.CategorizedProblem; +import org.eclipse.jdt.core.compiler.IProblem; + +/** + * Internal AST visitor for propagating syntax errors. + */ +class ASTSyntaxErrorPropagator extends ASTVisitor { + + private CategorizedProblem[] problems; + + ASTSyntaxErrorPropagator(CategorizedProblem[] problems) { + // visit Javadoc.tags() as well + super(true); + this.problems = problems; + } + + private boolean checkAndTagAsMalformed(ASTNode node) { + boolean tagWithErrors = false; + search: for (int i = 0, max = this.problems.length; i < max; i++) { + CategorizedProblem problem = this.problems[i]; + switch(problem.getID()) { + case IProblem.ParsingErrorOnKeywordNoSuggestion : + case IProblem.ParsingErrorOnKeyword : + case IProblem.ParsingError : + case IProblem.ParsingErrorNoSuggestion : + case IProblem.ParsingErrorInsertTokenBefore : + case IProblem.ParsingErrorInsertTokenAfter : + case IProblem.ParsingErrorDeleteToken : + case IProblem.ParsingErrorDeleteTokens : + case IProblem.ParsingErrorMergeTokens : + case IProblem.ParsingErrorInvalidToken : + case IProblem.ParsingErrorMisplacedConstruct : + case IProblem.ParsingErrorReplaceTokens : + case IProblem.ParsingErrorNoSuggestionForTokens : + case IProblem.ParsingErrorUnexpectedEOF : + case IProblem.ParsingErrorInsertToComplete : + case IProblem.ParsingErrorInsertToCompleteScope : + case IProblem.ParsingErrorInsertToCompletePhrase : + case IProblem.EndOfSource : + case IProblem.InvalidHexa : + case IProblem.InvalidOctal : + case IProblem.InvalidCharacterConstant : + case IProblem.InvalidEscape : + case IProblem.InvalidInput : + case IProblem.InvalidUnicodeEscape : + case IProblem.InvalidFloat : + case IProblem.NullSourceString : + case IProblem.UnterminatedString : + case IProblem.UnterminatedComment : + case IProblem.InvalidDigit : + break; + default: + continue search; + } + int position = problem.getSourceStart(); + int start = node.getStartPosition(); + int end = start + node.getLength(); + if ((start <= position) && (position <= end)) { + node.setFlags(node.getFlags() | ASTNode.MALFORMED); + // clear the bits on parent + ASTNode currentNode = node.getParent(); + while (currentNode != null) { + currentNode.setFlags(currentNode.getFlags() & ~ASTNode.MALFORMED); + currentNode = currentNode.getParent(); + } + tagWithErrors = true; + } + } + return tagWithErrors; + } + + /* + * Method declared on ASTVisitor. + */ + public boolean visit(FieldDeclaration node) { + return checkAndTagAsMalformed(node); + } + + /* + * Method declared on ASTVisitor. + */ + public boolean visit(MethodDeclaration node) { + return checkAndTagAsMalformed(node); + } + + /* + * Method declared on ASTVisitor. + */ + public boolean visit(PackageDeclaration node) { + return checkAndTagAsMalformed(node); + } + + /* + * Method declared on ASTVisitor. + */ + public boolean visit(ImportDeclaration node) { + return checkAndTagAsMalformed(node); + } + + /* + * Method declared on ASTVisitor. + */ + public boolean visit(CompilationUnit node) { + return checkAndTagAsMalformed(node); + } + + /* + * Method declared on ASTVisitor. + */ + public boolean visit(AnnotationTypeDeclaration node) { + return checkAndTagAsMalformed(node); + } + + /* + * Method declared on ASTVisitor. + */ + public boolean visit(EnumDeclaration node) { + return checkAndTagAsMalformed(node); + } + + /* + * Method declared on ASTVisitor. + */ + public boolean visit(TypeDeclaration node) { + return checkAndTagAsMalformed(node); + } + + /* + * Method declared on ASTVisitor. + */ + public boolean visit(Initializer node) { + return checkAndTagAsMalformed(node); + } + +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTVisitor.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTVisitor.java new file mode 100644 index 000000000..39ed372fb --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTVisitor.java @@ -0,0 +1,3052 @@ +/******************************************************************************* + * Copyright (c) 2000, 2009 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 + * $Id: ASTVisitor.java 22741 2009-10-13 22:23:05Z stephan $ + * + * Contributors: + * IBM Corporation - initial API and implementation + * Fraunhofer FIRST - extended API and implementation + * Technical University Berlin - extended API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +/** + * A visitor for abstract syntax trees. + * <p> + * For each different concrete AST node type <i>T</i> there are + * a pair of methods: + * <ul> + * <li><code>public boolean visit(<i>T</i> node)</code> - Visits + * the given node to perform some arbitrary operation. If <code>true</code> + * is returned, the given node's child nodes will be visited next; however, + * if <code>false</code> is returned, the given node's child nodes will + * not be visited. The default implementation provided by this class does + * nothing and returns <code>true</code> (with the exception of + * {@link #visit(Javadoc) ASTVisitor.visit(Javadoc)}). + * Subclasses may reimplement this method as needed.</li> + * <li><code>public void endVisit(<i>T</i> node)</code> - Visits + * the given node to perform some arbitrary operation. When used in the + * conventional way, this method is called after all of the given node's + * children have been visited (or immediately, if <code>visit</code> returned + * <code>false</code>). The default implementation provided by this class does + * nothing. Subclasses may reimplement this method as needed.</li> + * </ul> + * </p> + * In addition, there are a pair of methods for visiting AST nodes in the + * abstract, regardless of node type: + * <ul> + * <li><code>public void preVisit(ASTNode node)</code> - Visits + * the given node to perform some arbitrary operation. + * This method is invoked prior to the appropriate type-specific + * <code>visit</code> method. + * The default implementation of this method does nothing. + * Subclasses may reimplement this method as needed.</li> + * <li><code>public void postVisit(ASTNode node)</code> - Visits + * the given node to perform some arbitrary operation. + * This method is invoked after the appropriate type-specific + * <code>endVisit</code> method. + * The default implementation of this method does nothing. + * Subclasses may reimplement this method as needed.</li> + * </ul> + * <p> + * For nodes with list-valued properties, the child nodes within the list + * are visited in order. For nodes with multiple properties, the child nodes + * are visited in the order that most closely corresponds to the lexical + * reading order of the source program. For instance, for a type declaration + * node, the child ordering is: name, superclass, superinterfaces, and + * body declarations. + * </p> + * <p> + * While it is possible to modify the tree in the visitor, care is required to + * ensure that the consequences are as expected and desirable. + * During the course of an ordinary visit starting at a given node, every node + * in the subtree is visited exactly twice, first with <code>visit</code> and + * then with <code>endVisit</code>. During a traversal of a stationary tree, + * each node is either behind (after <code>endVisit</code>), ahead (before + * <code>visit</code>), or in progress (between <code>visit</code> and + * the matching <code>endVisit</code>). Changes to the "behind" region of the + * tree are of no consequence to the visit in progress. Changes to the "ahead" + * region will be taken in stride. Changes to the "in progress" portion are + * the more interesting cases. With a node, the various properties are arranged + * in a linear list, with a cursor that separates the properties that have + * been visited from the ones that are still to be visited (the cursor + * is between the elements, rather than on an element). The cursor moves from + * the head to the tail of this list, advancing to the next position just + * <i>before</i> <code>visit</code> if called for that child. After the child + * subtree has been completely visited, the visit moves on the child + * immediately after the cursor. Removing a child while it is being visited + * does not alter the course of the visit. But any children added at positions + * after the cursor are considered in the "ahead" portion and will be visited. + * </p> + * <p> + * Cases to watch out for: + * <ul> + * <li>Moving a child node further down the list. This could result in the + * child subtree being visited multiple times; these visits are sequential.</li> + * <li>Moving a child node up into an ancestor. If the new home for + * the node is in the "ahead" portion, the subtree will be visited + * a second time; again, these visits are sequential.</li> + * <li>Moving a node down into a child. If the new home for + * the node is in the "ahead" portion, the subtree will be visited + * a second time; in this case, the visits will be nested. In some cases, + * this can lead to a stack overflow or out of memory condition.</li> + * </ul> + * <p>Note that {@link LineComment} and {@link BlockComment} nodes are + * not normally visited in an AST because they are not considered + * part of main structure of the AST. Use + * {@link CompilationUnit#getCommentList()} to find these additional + * comments nodes. + * </p> + * + * @see org.eclipse.jdt.core.dom.ASTNode#accept(ASTVisitor) + */ +public abstract class ASTVisitor { + + /** + * Indicates whether doc tags should be visited by default. + * @since 3.0 + */ + private boolean visitDocTags; + + /** + * Creates a new AST visitor instance. + * <p> + * For backwards compatibility, the visitor does not visit tag + * elements below doc comments by default. Use + * {@link #ASTVisitor(boolean) ASTVisitor(true)} + * for an visitor that includes doc comments by default. + * </p> + */ + public ASTVisitor() { + this(false); + } + + /** + * Creates a new AST visitor instance. + * + * @param visitDocTags <code>true</code> if doc comment tags are + * to be visited by default, and <code>false</code> otherwise + * @see Javadoc#tags() + * @see #visit(Javadoc) + * @since 3.0 + */ + public ASTVisitor(boolean visitDocTags) { + this.visitDocTags = visitDocTags; + } + + /** + * Visits the given AST node prior to the type-specific visit + * (before <code>visit</code>). + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * + * @see #preVisit2(ASTNode) + */ + public void preVisit(ASTNode node) { + // default implementation: do nothing + } + + /** + * Visits the given AST node prior to the type-specific visit (before <code>visit</code>). + * <p> + * The default implementation calls {@link #preVisit(ASTNode)} and then + * returns true. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if <code>visit(node)</code> should be called, + * and <code>false</code> otherwise. + * @see #preVisit(ASTNode) + * @since 3.5 + */ + public boolean preVisit2(ASTNode node) { + preVisit(node); + return true; + } + + /** + * Visits the given AST node following the type-specific visit + * (after <code>endVisit</code>). + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void postVisit(ASTNode node) { + // default implementation: do nothing + } + + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + * @since 3.1 + */ + public boolean visit(AnnotationTypeDeclaration node) { + return true; + } + + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + * @since 3.1 + */ + public boolean visit(AnnotationTypeMemberDeclaration node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(AnonymousClassDeclaration node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(ArrayAccess node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(ArrayCreation node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(ArrayInitializer node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(ArrayType node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(AssertStatement node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(Assignment node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(Block node) { + return true; + } + + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * <p>Note: {@link LineComment} and {@link BlockComment} nodes are + * not considered part of main structure of the AST. This method will + * only be called if a client goes out of their way to visit this + * kind of node explicitly. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + * @since 3.0 + */ + public boolean visit(BlockComment node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(BooleanLiteral node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(BreakStatement node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(CastExpression node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(CatchClause node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(CharacterLiteral node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(ClassInstanceCreation node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(CompilationUnit node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(ConditionalExpression node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(ConstructorInvocation node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(ContinueStatement node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(DoStatement node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(EmptyStatement node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + * @since 3.1 + */ + public boolean visit(EnhancedForStatement node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + * @since 3.1 + */ + public boolean visit(EnumConstantDeclaration node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + * @since 3.1 + */ + public boolean visit(EnumDeclaration node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(ExpressionStatement node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(FieldAccess node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(FieldDeclaration node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(ForStatement node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(IfStatement node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(ImportDeclaration node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(InfixExpression node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(InstanceofExpression node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(Initializer node) { + return true; + } + + /** + * Visits the given AST node. + * <p> + * Unlike other node types, the boolean returned by the default + * implementation is controlled by a constructor-supplied + * parameter {@link #ASTVisitor(boolean) ASTVisitor(boolean)} + * which is <code>false</code> by default. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + * @see #ASTVisitor() + * @see #ASTVisitor(boolean) + */ + public boolean visit(Javadoc node) { + // visit tag elements inside doc comments only if requested + return this.visitDocTags; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(LabeledStatement node) { + return true; + } + + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * <p>Note: {@link LineComment} and {@link BlockComment} nodes are + * not considered part of main structure of the AST. This method will + * only be called if a client goes out of their way to visit this + * kind of node explicitly. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + * @since 3.0 + */ + public boolean visit(LineComment node) { + return true; + } + + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + * @since 3.1 + */ + public boolean visit(MarkerAnnotation node) { + return true; + } + + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + * @since 3.0 + */ + public boolean visit(MemberRef node) { + return true; + } + + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + * @since 3.1 + */ + public boolean visit(MemberValuePair node) { + return true; + } + + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + * @since 3.0 + */ + public boolean visit(MethodRef node) { + return true; + } + + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + * @since 3.0 + */ + public boolean visit(MethodRefParameter node) { + return true; + } + + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(MethodDeclaration node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(MethodInvocation node) { + return true; + } + + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + * @since 3.1 + */ + public boolean visit(Modifier node) { + return true; + } + + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + * @since 3.1 + */ + public boolean visit(NormalAnnotation node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(NullLiteral node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(NumberLiteral node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(PackageDeclaration node) { + return true; + } + + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + * @since 3.1 + */ + public boolean visit(ParameterizedType node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(ParenthesizedExpression node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(PostfixExpression node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(PrefixExpression node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(PrimitiveType node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(QualifiedName node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + * @since 3.1 + */ + public boolean visit(QualifiedType node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(ReturnStatement node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(SimpleName node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(SimpleType node) { + return true; + } + + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + * @since 3.1 + */ + public boolean visit(SingleMemberAnnotation node) { + return true; + } + + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(SingleVariableDeclaration node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(StringLiteral node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(SuperConstructorInvocation node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(SuperFieldAccess node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(SuperMethodInvocation node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(SwitchCase node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(SwitchStatement node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(SynchronizedStatement node) { + return true; + } + + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + * @since 3.0 + */ + public boolean visit(TagElement node) { + return true; + } + + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + * @since 3.0 + */ + public boolean visit(TextElement node) { + return true; + } + + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(ThisExpression node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(ThrowStatement node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(TryStatement node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(TypeDeclaration node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(TypeDeclarationStatement node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(TypeLiteral node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + * @since 3.1 + */ + public boolean visit(TypeParameter node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(VariableDeclarationExpression node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(VariableDeclarationStatement node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(VariableDeclarationFragment node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(WhileStatement node) { + return true; + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + * @since 3.1 + */ + public boolean visit(WildcardType node) { + return true; + } + +//{ObjectTeams: visit methods for OT-specific types + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(MethodSpec node) + { + return visitNode(node); + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(FieldAccessSpec node) + { + return visitNode(node); + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(CallinMappingDeclaration node) + { + return visitNode(node); + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(CalloutMappingDeclaration node) + { + return visitNode(node); + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and returns true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + * @since 1.3.1 + */ + public boolean visit(MethodBindingOperator node) { + return visitNode(node); + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(LiftingType node) + { + return visitNode(node); + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(TypeAnchor node) + { + return visitNode(node); + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + * @since 3.0 + */ + public boolean visit(ParameterMapping node) + { + return visitNode(node); + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + * @since 3.0 + */ + public boolean visit(RoleTypeDeclaration node) + { + return visitNode(node); + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(WithinStatement node) + { + return visitNode(node); + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(TSuperMessageSend node) + { + return visitNode(node); + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(TSuperConstructorInvocation node) + { + return visitNode(node); + } + + + + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(BaseCallMessageSend node) + { + return visitNode(node); + } + + /** + * Visits the given type-specific AST node. + * <p> + * The default implementation does nothing and return true. + * Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @return <code>true</code> if the children of this node should be + * visited, and <code>false</code> if the children of this node should + * be skipped + */ + public boolean visit(BaseConstructorInvocation node) + { + return visitNode(node); + } + + public boolean visit(PrecedenceDeclaration node) { + return visitNode(node); + } + + public boolean visit(GuardPredicateDeclaration node) { + return visitNode(node); + } +//gbr} + +//{ObjectTeams: adapt subclass org.eclipse.jdt.internal.corext.dom.GenericVisitor: + // introduce method to which others will be mapped + protected boolean visitNode(ASTNode node) { + return true; + } + +// SH} + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @since 3.1 + */ + public void endVisit(AnnotationTypeDeclaration node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @since 3.1 + */ + public void endVisit(AnnotationTypeMemberDeclaration node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(AnonymousClassDeclaration node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(ArrayAccess node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(ArrayCreation node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(ArrayInitializer node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(ArrayType node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(AssertStatement node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(Assignment node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(Block node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * <p>Note: {@link LineComment} and {@link BlockComment} nodes are + * not considered part of main structure of the AST. This method will + * only be called if a client goes out of their way to visit this + * kind of node explicitly. + * </p> + * + * @param node the node to visit + * @since 3.0 + */ + public void endVisit(BlockComment node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(BooleanLiteral node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(BreakStatement node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(CastExpression node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(CatchClause node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(CharacterLiteral node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(ClassInstanceCreation node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(CompilationUnit node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(ConditionalExpression node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(ConstructorInvocation node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(ContinueStatement node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(DoStatement node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(EmptyStatement node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @since 3.1 + */ + public void endVisit(EnhancedForStatement node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @since 3.1 + */ + public void endVisit(EnumConstantDeclaration node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @since 3.1 + */ + public void endVisit(EnumDeclaration node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(ExpressionStatement node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(FieldAccess node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(FieldDeclaration node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(ForStatement node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(IfStatement node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(ImportDeclaration node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(InfixExpression node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(InstanceofExpression node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(Initializer node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(Javadoc node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(LabeledStatement node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * <p>Note: {@link LineComment} and {@link BlockComment} nodes are + * not considered part of main structure of the AST. This method will + * only be called if a client goes out of their way to visit this + * kind of node explicitly. + * </p> + * + * @param node the node to visit + * @since 3.0 + */ + public void endVisit(LineComment node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @since 3.1 + */ + public void endVisit(MarkerAnnotation node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @since 3.0 + */ + public void endVisit(MemberRef node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @since 3.1 + */ + public void endVisit(MemberValuePair node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @since 3.0 + */ + public void endVisit(MethodRef node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @since 3.0 + */ + public void endVisit(MethodRefParameter node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(MethodDeclaration node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(MethodInvocation node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @since 3.1 + */ + public void endVisit(Modifier node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @since 3.1 + */ + public void endVisit(NormalAnnotation node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(NullLiteral node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(NumberLiteral node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(PackageDeclaration node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @since 3.1 + */ + public void endVisit(ParameterizedType node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(ParenthesizedExpression node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(PostfixExpression node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(PrefixExpression node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(PrimitiveType node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(QualifiedName node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @since 3.1 + */ + public void endVisit(QualifiedType node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(ReturnStatement node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(SimpleName node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(SimpleType node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @since 3.1 + */ + public void endVisit(SingleMemberAnnotation node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(SingleVariableDeclaration node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(StringLiteral node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(SuperConstructorInvocation node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(SuperFieldAccess node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(SuperMethodInvocation node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(SwitchCase node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(SwitchStatement node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(SynchronizedStatement node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @since 3.0 + */ + public void endVisit(TagElement node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @since 3.0 + */ + public void endVisit(TextElement node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(ThisExpression node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(ThrowStatement node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(TryStatement node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(TypeDeclaration node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(TypeDeclarationStatement node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(TypeLiteral node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @since 3.1 + */ + public void endVisit(TypeParameter node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(VariableDeclarationExpression node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(VariableDeclarationStatement node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(VariableDeclarationFragment node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(WhileStatement node) { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @since 3.1 + */ + public void endVisit(WildcardType node) { + // default implementation: do nothing + } + +//{ObjectTeams: endVisit methods for OT-specific types + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(MethodSpec node) + { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(FieldAccessSpec node) + { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(CallinMappingDeclaration node) + { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(CalloutMappingDeclaration node) + { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + * @since 1.3.1 + */ + public void endVisit(MethodBindingOperator node) + { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(ParameterMapping node) + { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(RoleTypeDeclaration node) + { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(LiftingType node) + { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(TypeAnchor node) + { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(WithinStatement node) + { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(TSuperMessageSend node) + { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(TSuperConstructorInvocation node) + { + // default implementation: do nothing + } + + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(BaseConstructorInvocation node) + { + // default implementation: do nothing + } + + /** + * End of visit the given type-specific AST node. + * <p> + * The default implementation does nothing. Subclasses may reimplement. + * </p> + * + * @param node the node to visit + */ + public void endVisit(BaseCallMessageSend node) + { + // default implementation: do nothing + } + + public void endVisit(PrecedenceDeclaration declaration) + { + // default implementation: do nothing + } + + public void endVisit(GuardPredicateDeclaration predicate) { + // default implementation: do nothing + } + +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AbstractMethodMappingDeclaration.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AbstractMethodMappingDeclaration.java new file mode 100644 index 000000000..bc1c86e3e --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AbstractMethodMappingDeclaration.java @@ -0,0 +1,205 @@ +/********************************************************************** + * This file is part of "Object Teams Development Tooling"-Software + * + * Copyright 2004, 2006 Fraunhofer Gesellschaft, Munich, Germany, + * for its Fraunhofer Institute for Computer Architecture and Software + * Technology (FIRST), Berlin, Germany and Technical University Berlin, + * Germany. + * + * 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 + * $Id: AbstractMethodMappingDeclaration.java 23416 2010-02-03 19:59:31Z stephan $ + * + * Please visit http://www.eclipse.org/objectteams for updates and contact. + * + * Contributors: + * Fraunhofer FIRST - Initial API and implementation + * Technical University Berlin - Initial API and implementation + **********************************************************************/ +package org.eclipse.jdt.core.dom; + +import java.util.List; + +/** + * NEW for OTDT. + * + * Super class for callin/callout method mappings + * @author brcan + * + * $Id: AbstractMethodMappingDeclaration.java 23416 2010-02-03 19:59:31Z stephan $ + */ +public abstract class AbstractMethodMappingDeclaration extends BodyDeclaration +{ + + protected MethodMappingElement roleMappingElement = null; + + // includes info about binding kind and binding modifiers + protected MethodBindingOperator bindingOperator = null; + + /** + * Creates a new AST node for an abstract method mapping declaration node owned by + * the given AST. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + AbstractMethodMappingDeclaration(AST ast) + { + super(ast); + } + + /** + * The list of parameter mappings (element type: <code>ParameterMapping</code>). + * Defaults to an empty list. + */ + ASTNode.NodeList _parameterMappings = + new ASTNode.NodeList(internalParameterMappingsProperty()); + + /** Return the structural property descriptor for the roleMappingElement property of this node. */ + abstract ChildPropertyDescriptor internalGetRoleElementProperty(); + + /** Return the structural property descriptor for the bindingOperator property of this node. */ + abstract ChildPropertyDescriptor internalGetBindingOperatorProperty(); + + /** + * Returns structural property descriptor for the "parameterMappings" property + * of this node. + * + * @return the property descriptor + */ + abstract ChildListPropertyDescriptor internalParameterMappingsProperty(); + + /** + * Creates and returns a structural property descriptor for the + * "parameterMappings" property declared on the given concrete node type. + * + * @return the property descriptor + */ + static final ChildListPropertyDescriptor internalParameterMappingPropertyFactory(Class nodeClass) + { + return new ChildListPropertyDescriptor(nodeClass, "parameterMappings", ParameterMapping.class, CYCLE_RISK); //$NON-NLS-1$ + } + + ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) + { + if (property == internalGetRoleElementProperty()) + { + if (get) { + return getRoleMappingElement(); + } else { + setRoleMappingElement((MethodSpec) child); + return null; + } + } + if (property == internalGetBindingOperatorProperty()) + { + if (get) { + return bindingOperator(); + } else { + setBindingOperator((MethodBindingOperator)child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + + /** + * Returns the method spec left of the callout/in arrow. + * @return the left method spec, i.e. the declaring role method + */ + public MethodMappingElement getRoleMappingElement() + { + if (this.roleMappingElement == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.roleMappingElement == null) { + preLazyInit(); + this.roleMappingElement = new MethodSpec(this.ast); + postLazyInit(this.roleMappingElement, internalGetRoleElementProperty()); + } + } + } + return this.roleMappingElement; + } + + /** + * Sets the left method spec (role method spec) declared in this callout + * mapping declaration to the given method spec. + * + * @param roleMappingElement + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public void setRoleMappingElement(MethodMappingElement roleMappingElement) + { + if (roleMappingElement == null) + { + throw new IllegalArgumentException(); + } + ASTNode oldChild = roleMappingElement; + preReplaceChild(oldChild, roleMappingElement, internalGetRoleElementProperty()); + this.roleMappingElement = roleMappingElement; + postReplaceChild(oldChild, roleMappingElement, internalGetRoleElementProperty()); + } + + + public void setBindingOperator(MethodBindingOperator bindingOp) { + ChildPropertyDescriptor propertyDescriptor = internalGetBindingOperatorProperty(); + MethodBindingOperator oldOperator = this.bindingOperator; + preReplaceChild(oldOperator, bindingOp, propertyDescriptor); + this.bindingOperator = bindingOp; + postReplaceChild(oldOperator, bindingOp, propertyDescriptor); + } + + public MethodBindingOperator bindingOperator() { + if (this.bindingOperator == null) + { + // lazy init must be thread-safe for readers + synchronized (this) + { + if (this.bindingOperator == null) + { + preLazyInit(); + this.bindingOperator = new MethodBindingOperator(this.ast); + postLazyInit(this.bindingOperator, internalGetBindingOperatorProperty()); + } + } + } + return this.bindingOperator; + } + + /** + * Returns the live ordered list of parameter mappings for this + * callin mapping declaration. + * + * @return the live list of parameter mappings + * (element type: <code>ParameterMapping</code>) + */ + public List getParameterMappings() + { + return _parameterMappings; + } + + public boolean hasParameterMapping() + { + return (! _parameterMappings.isEmpty()); + } + + public boolean hasSignature() { + return getRoleMappingElement().hasSignature(); + } + + public IMethodMappingBinding resolveBinding() + { + return this.ast.getBindingResolver().resolveMethodMapping(this); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AbstractTypeDeclaration.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AbstractTypeDeclaration.java new file mode 100644 index 000000000..031f49882 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AbstractTypeDeclaration.java @@ -0,0 +1,281 @@ +/******************************************************************************* + * Copyright (c) 2004, 2009 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: + * IBM Corporation - initial API and implementation + * Technical University Berlin - extended API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.dom; + +import java.util.List; + +/** + * Abstract subclass for type declaration, enum declaration, + * and annotation type declaration AST node types. + * <pre> + * AbstractTypeDeclaration: + * TypeDeclaration + * EnumDeclaration + * AnnotationTypeDeclaration + * </pre> + * + * @since 3.0 + */ +public abstract class AbstractTypeDeclaration extends BodyDeclaration { + + /** + * The type name; lazily initialized; defaults to a unspecified, + * legal Java class identifier. + * @since 2.0 (originally declared on <code>TypeDeclaration</code>) + */ + SimpleName typeName = null; + + /** + * The body declarations (element type: <code>BodyDeclaration</code>). + * Defaults to an empty list. + * @since 2.0 (originally declared on <code>TypeDeclaration</code>) + */ + ASTNode.NodeList bodyDeclarations; + + /** + * Returns structural property descriptor for the "bodyDeclarations" property + * of this node. + * + * @return the property descriptor + */ + abstract ChildListPropertyDescriptor internalBodyDeclarationsProperty(); + + /** + * Returns structural property descriptor for the "bodyDeclarations" property + * of this node. + * + * @return the property descriptor + * @since 3.1 + */ + public final ChildListPropertyDescriptor getBodyDeclarationsProperty() { + return internalBodyDeclarationsProperty(); + } + + /** + * Returns structural property descriptor for the "name" property + * of this node. + * + * @return the property descriptor + */ + abstract ChildPropertyDescriptor internalNameProperty(); + + /** + * Returns structural property descriptor for the "name" property + * of this node. + * + * @return the property descriptor + * @since 3.1 + */ + public final ChildPropertyDescriptor getNameProperty() { + return internalNameProperty(); + } + + /** + * Creates and returns a structural property descriptor for the + * "bodyDeclaration" property declared on the given concrete node type. + * + * @return the property descriptor + */ + static final ChildListPropertyDescriptor internalBodyDeclarationPropertyFactory(Class nodeClass) { + return new ChildListPropertyDescriptor(nodeClass, "bodyDeclarations", BodyDeclaration.class, CYCLE_RISK); //$NON-NLS-1$ + } + + /** + * Creates and returns a structural property descriptor for the + * "name" property declared on the given concrete node type. + * + * @return the property descriptor + */ + static final ChildPropertyDescriptor internalNamePropertyFactory(Class nodeClass) { + return new ChildPropertyDescriptor(nodeClass, "name", SimpleName.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$ + } + + /** + * Creates a new AST node for an abstract type declaration owned by the given + * AST. + * <p> + * N.B. This constructor is package-private; all subclasses must be + * declared in the same package; clients are unable to declare + * additional subclasses. + * </p> + * + * @param ast the AST that is to own this node + */ + AbstractTypeDeclaration(AST ast) { + super(ast); + this.bodyDeclarations = new ASTNode.NodeList(internalBodyDeclarationsProperty()); + } + + /** + * Returns the name of the type declared in this type declaration. + * + * @return the type name node + * @since 2.0 (originally declared on <code>TypeDeclaration</code>) + */ + public SimpleName getName() { + if (this.typeName == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.typeName == null) { + preLazyInit(); + this.typeName = new SimpleName(this.ast); + postLazyInit(this.typeName, internalNameProperty()); + } + } + } + return this.typeName; + } + + /** + * Sets the name of the type declared in this type declaration to the + * given name. + * + * @param typeName the new type name + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + * @since 2.0 (originally declared on <code>TypeDeclaration</code>) + */ + public void setName(SimpleName typeName) { + if (typeName == null) { + throw new IllegalArgumentException(); + } + ChildPropertyDescriptor p = internalNameProperty(); + ASTNode oldChild = this.typeName; + preReplaceChild(oldChild, typeName, p); + this.typeName = typeName; + postReplaceChild(oldChild, typeName, p); + } + + /** + * Returns the live ordered list of body declarations of this type + * declaration. + * + * @return the live list of body declarations + * (element type: <code>BodyDeclaration</code>) + * @since 2.0 (originally declared on <code>TypeDeclaration</code>) + */ + public List bodyDeclarations() { + return this.bodyDeclarations; + } + + /** + * Returns whether this type declaration is a package member (that is, + * a top-level type). + * <p> + * Note that this is a convenience method that simply checks whether + * this node's parent is a compilation unit node. + * </p> + * + * @return <code>true</code> if this type declaration is a child of + * a compilation unit node, and <code>false</code> otherwise + * @since 2.0 (originally declared on <code>TypeDeclaration</code>) + */ + public boolean isPackageMemberTypeDeclaration() { + ASTNode parent = getParent(); + return (parent instanceof CompilationUnit); + } + + /** + * Returns whether this type declaration is a type member. + * <p> + * Note that this is a convenience method that simply checks whether + * this node's parent is a type declaration node or an anonymous + * class declaration. + * </p> + * + * @return <code>true</code> if this type declaration is a child of + * a type declaration node or an anonymous class declaration node, + * and <code>false</code> otherwise + * @since 2.0 (originally declared on <code>TypeDeclaration</code>) + */ + public boolean isMemberTypeDeclaration() { + ASTNode parent = getParent(); + return (parent instanceof AbstractTypeDeclaration) + || (parent instanceof AnonymousClassDeclaration); + } + + /** + * Returns whether this type declaration is a local type. + * <p> + * Note that this is a convenience method that simply checks whether + * this node's parent is a type declaration statement node. + * </p> + * + * @return <code>true</code> if this type declaration is a child of + * a type declaration statement node, and <code>false</code> otherwise + * @since 2.0 (originally declared on <code>TypeDeclaration</code>) + */ + public boolean isLocalTypeDeclaration() { + ASTNode parent = getParent(); + return (parent instanceof TypeDeclarationStatement); + } + +//{ObjectTeams: additional queries: + /** + * Returns whether this type declaration is a team type. + * + * @return <code>true</code> if this type declaration is a team declaration, + * and <code>false</code> otherwise + * @since OTDT_1.2.3 + */ + public boolean isTeam() { + return false; + } + + /** + * Returns whether this type declaration is a role type. + * + * @return <code>true</code> if this type declaration is a role declaration, + * and <code>false</code> otherwise + * @since OTDT_1.2.3 + */ + public boolean isRole() { + return false; + } +// SH} + + /** + * Resolves and returns the binding for the type declared in this type + * declaration. + * <p> + * Note that bindings are generally unavailable unless requested when the + * AST is being built. + * </p> + * + * @return the binding, or <code>null</code> if the binding cannot be + * resolved + * @since 3.1 Declared in 3.0 on the individual subclasses. + */ + public final ITypeBinding resolveBinding() { + return internalResolveBinding(); + } + + /** + * Resolves and returns the binding for the type declared in this type + * declaration. This method must be implemented by subclasses. + * + * @return the binding, or <code>null</code> if the binding cannot be + * resolved + */ + abstract ITypeBinding internalResolveBinding(); + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return super.memSize() + 2 * 4; + } + +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Annotation.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Annotation.java new file mode 100644 index 000000000..6d22f007a --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Annotation.java @@ -0,0 +1,181 @@ +/******************************************************************************* + * Copyright (c) 2004, 2009 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.dom; + +/** + * Abstract base class of AST nodes that represent annotations. + * <p> + * <pre> + * Annotation: + * NormalAnnotation + * MarkerAnnotation + * SingleMemberAnnotation + * </pre> + * </p> + * @since 3.1 + */ +public abstract class Annotation extends Expression implements IExtendedModifier { + + /** + * Returns structural property descriptor for the "typeName" property + * of this node. + * + * @return the property descriptor + */ + abstract ChildPropertyDescriptor internalTypeNameProperty(); + + /** + * Returns structural property descriptor for the "typeName" property + * of this node. + * + * @return the property descriptor + */ + public final ChildPropertyDescriptor getTypeNameProperty() { + return internalTypeNameProperty(); + } + + /** + * Creates and returns a structural property descriptor for the + * "typeName" property declared on the given concrete node type. + * + * @return the property descriptor + */ + static final ChildPropertyDescriptor internalTypeNamePropertyFactory(Class nodeClass) { + return new ChildPropertyDescriptor(nodeClass, "typeName", Name.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$ + } + + /** + * The annotation type name; lazily initialized; defaults to an unspecified, + * legal Java identifier. + */ + Name typeName = null; + + /** + * Creates a new AST node for an annotation node owned by the + * given AST. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + Annotation(AST ast) { + super(ast); + } + + /** + * @see IExtendedModifier#isModifier() + */ + public boolean isModifier() { + return false; + } + + /** + * @see IExtendedModifier#isAnnotation() + */ + public boolean isAnnotation() { + return true; + } + + /** + * Returns the annotation type name of this annotation. + * + * @return the annotation type name + */ + public Name getTypeName() { + if (this.typeName == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.typeName == null) { + preLazyInit(); + this.typeName = new SimpleName(this.ast); + postLazyInit(this.typeName, internalTypeNameProperty()); + } + } + } + return this.typeName; + } + + /** + * Sets the annotation type name of this annotation. + * + * @param typeName the annotation type name + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public void setTypeName(Name typeName) { + if (typeName == null) { + throw new IllegalArgumentException(); + } + ChildPropertyDescriptor p = internalTypeNameProperty(); + ASTNode oldChild = this.typeName; + preReplaceChild(oldChild, typeName, p); + this.typeName = typeName; + postReplaceChild(oldChild, typeName, p); + } + + /** + * Returns whether this is a normal annotation + * ({@link NormalAnnotation}). + * + * @return <code>true</code> if this is a normal annotation, + * and <code>false</code> otherwise + */ + public boolean isNormalAnnotation() { + return (this instanceof NormalAnnotation); + } + + /** + * Returns whether this is a marker annotation + * ({@link MarkerAnnotation}). + * + * @return <code>true</code> if this is a marker annotation, + * and <code>false</code> otherwise + */ + public boolean isMarkerAnnotation() { + return (this instanceof MarkerAnnotation); + } + + /** + * Returns whether this is a single member annotation. + * ({@link SingleMemberAnnotation}). + * + * @return <code>true</code> if this is a single member annotation, + * and <code>false</code> otherwise + */ + public boolean isSingleMemberAnnotation() { + return (this instanceof SingleMemberAnnotation); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return BASE_NODE_SIZE + 1 * 4; + } + + /** + * Resolves and returns the resolved annotation for this annotation. + * <p> + * Note that bindings (which includes resolved annotations) are generally unavailable unless + * requested when the AST is being built. + * </p> + * + * @return the resolved annotation, or <code>null</code> if the annotation cannot be resolved + * @since 3.2 + */ + public IAnnotationBinding resolveAnnotationBinding() { + return this.ast.getBindingResolver().resolveAnnotation(this); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AnnotationBinding.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AnnotationBinding.java new file mode 100644 index 000000000..106cf7b41 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AnnotationBinding.java @@ -0,0 +1,249 @@ +/******************************************************************************* + * Copyright (c) 2005, 2008 BEA Systems, Inc. + * 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: + * tyeung@bea.com - initial API and implementation + * IBM Corporation - implemented methods from IBinding + * IBM Corporation - renamed from ResolvedAnnotation to AnnotationBinding + *******************************************************************************/ +package org.eclipse.jdt.core.dom; + +import org.eclipse.jdt.core.IAnnotatable; +import org.eclipse.jdt.core.ICompilationUnit; +import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.core.IMember; +import org.eclipse.jdt.internal.compiler.lookup.ElementValuePair; +import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; +import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; +import org.eclipse.jdt.internal.compiler.lookup.TagBits; +import org.eclipse.jdt.internal.compiler.util.*; + +/** + * Internal class + */ +class AnnotationBinding implements IAnnotationBinding { + static final AnnotationBinding[] NoAnnotations = new AnnotationBinding[0]; + private org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding binding; + private BindingResolver bindingResolver; + private String key; + + AnnotationBinding(org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding annotation, BindingResolver resolver) { + if (annotation == null) + throw new IllegalStateException(); + this.binding = annotation; + this.bindingResolver = resolver; + } + + public IAnnotationBinding[] getAnnotations() { + return NoAnnotations; + } + + public ITypeBinding getAnnotationType() { + ITypeBinding typeBinding = this.bindingResolver.getTypeBinding(this.binding.getAnnotationType()); + if (typeBinding == null) + return null; + return typeBinding; + } + + public IMemberValuePairBinding[] getDeclaredMemberValuePairs() { + ReferenceBinding typeBinding = this.binding.getAnnotationType(); + if (typeBinding == null || ((typeBinding.tagBits & TagBits.HasMissingType) != 0)) { + return MemberValuePairBinding.NoPair; + } + ElementValuePair[] internalPairs = this.binding.getElementValuePairs(); + int length = internalPairs.length; + IMemberValuePairBinding[] pairs = length == 0 ? MemberValuePairBinding.NoPair : new MemberValuePairBinding[length]; + int counter = 0; + for (int i = 0; i < length; i++) { + ElementValuePair valuePair = internalPairs[i]; + if (valuePair.binding == null) continue; + pairs[counter++] = this.bindingResolver.getMemberValuePairBinding(valuePair); + } + if (counter == 0) return MemberValuePairBinding.NoPair; + if (counter != length) { + // resize + System.arraycopy(pairs, 0, (pairs = new MemberValuePairBinding[counter]), 0, counter); + } + return pairs; + } + + public IMemberValuePairBinding[] getAllMemberValuePairs() { + IMemberValuePairBinding[] pairs = getDeclaredMemberValuePairs(); + ReferenceBinding typeBinding = this.binding.getAnnotationType(); + if (typeBinding == null || ((typeBinding.tagBits & TagBits.HasMissingType) != 0)) return pairs; + MethodBinding[] methods = typeBinding.availableMethods(); // resilience + int methodLength = methods == null ? 0 : methods.length; + if (methodLength == 0) return pairs; + + int declaredLength = pairs.length; + if (declaredLength == methodLength) + return pairs; + + HashtableOfObject table = new HashtableOfObject(declaredLength); + for (int i = 0; i < declaredLength; i++) { + char[] internalName = ((MemberValuePairBinding) pairs[i]).internalName(); + if (internalName == null) continue; + table.put(internalName, pairs[i]); + } + + // handle case of more methods than declared members + IMemberValuePairBinding[] allPairs = new IMemberValuePairBinding[methodLength]; + for (int i = 0; i < methodLength; i++) { + Object pair = table.get(methods[i].selector); + allPairs[i] = pair == null ? new DefaultValuePairBinding(methods[i], this.bindingResolver) : (IMemberValuePairBinding) pair; + } + return allPairs; + } + + public IJavaElement getJavaElement() { + if (!(this.bindingResolver instanceof DefaultBindingResolver)) return null; + ASTNode node = (ASTNode) ((DefaultBindingResolver) this.bindingResolver).bindingsToAstNodes.get(this); + if (!(node instanceof Annotation)) return null; + ASTNode parent = node.getParent(); + IJavaElement parentElement = null; + switch (parent.getNodeType()) { + case ASTNode.PACKAGE_DECLARATION: + IJavaElement cu = ((CompilationUnit) parent.getParent()).getJavaElement(); + if (cu instanceof ICompilationUnit) { + String pkgName = ((PackageDeclaration) parent).getName().getFullyQualifiedName(); + parentElement = ((ICompilationUnit) cu).getPackageDeclaration(pkgName); + } + break; + case ASTNode.ENUM_DECLARATION: + case ASTNode.TYPE_DECLARATION: + case ASTNode.ANNOTATION_TYPE_DECLARATION: + parentElement = ((AbstractTypeDeclaration) parent).resolveBinding().getJavaElement(); + break; + case ASTNode.FIELD_DECLARATION: + VariableDeclarationFragment fragment = (VariableDeclarationFragment) ((FieldDeclaration) parent).fragments().get(0); + parentElement = fragment.resolveBinding().getJavaElement(); + break; + case ASTNode.METHOD_DECLARATION: + parentElement = ((MethodDeclaration) parent).resolveBinding().getJavaElement(); + break; + case ASTNode.VARIABLE_DECLARATION_STATEMENT: + fragment = (VariableDeclarationFragment) ((VariableDeclarationStatement) parent).fragments().get(0); + parentElement = fragment.resolveBinding().getJavaElement(); + break; + default: + return null; + } + if (! (parentElement instanceof IAnnotatable)) return null; + if ((parentElement instanceof IMember) && ((IMember) parentElement).isBinary()) { + return ((IAnnotatable) parentElement).getAnnotation(getAnnotationType().getQualifiedName()); + } + return ((IAnnotatable) parentElement).getAnnotation(getName()); + } + + public String getKey() { + if (this.key == null) { + String recipientKey = getRecipientKey(); + this.key = new String(this.binding.computeUniqueKey(recipientKey.toCharArray())); + } + return this.key; + } + + private String getRecipientKey() { + if (!(this.bindingResolver instanceof DefaultBindingResolver)) return ""; //$NON-NLS-1$ + DefaultBindingResolver resolver = (DefaultBindingResolver) this.bindingResolver; + ASTNode node = (ASTNode) resolver.bindingsToAstNodes.get(this); + if (node == null) { + // Can happen if annotation bindings have been resolved before having parsed the declaration + return ""; //$NON-NLS-1$ + } + ASTNode recipient = node.getParent(); + switch (recipient.getNodeType()) { + case ASTNode.PACKAGE_DECLARATION: + String pkgName = ((PackageDeclaration) recipient).getName().getFullyQualifiedName(); + return pkgName.replace('.', '/'); + case ASTNode.TYPE_DECLARATION: + return ((TypeDeclaration) recipient).resolveBinding().getKey(); + case ASTNode.FIELD_DECLARATION: + VariableDeclarationFragment fragment = (VariableDeclarationFragment) ((FieldDeclaration) recipient).fragments().get(0); + return fragment.resolveBinding().getKey(); + case ASTNode.METHOD_DECLARATION: + return ((MethodDeclaration) recipient).resolveBinding().getKey(); + case ASTNode.VARIABLE_DECLARATION_STATEMENT: + fragment = (VariableDeclarationFragment) ((VariableDeclarationStatement) recipient).fragments().get(0); + return fragment.resolveBinding().getKey(); + default: + return ""; //$NON-NLS-1$ + } + } + + public int getKind() { + return IBinding.ANNOTATION; + } + + public int getModifiers() { + return Modifier.NONE; + } + + public String getName() { + ITypeBinding annotationType = getAnnotationType(); + if (annotationType == null) { + return new String(this.binding.getAnnotationType().sourceName()); + } else { + return annotationType.getName(); + } + } + + public boolean isDeprecated() { + ReferenceBinding typeBinding = this.binding.getAnnotationType(); + if (typeBinding == null) return false; + return typeBinding.isDeprecated(); + } + + public boolean isEqualTo(IBinding otherBinding) { + if (this == otherBinding) + return true; + if (otherBinding.getKind() != IBinding.ANNOTATION) + return false; + IAnnotationBinding other = (IAnnotationBinding) otherBinding; + if (!getAnnotationType().isEqualTo(other.getAnnotationType())) + return false; + IMemberValuePairBinding[] memberValuePairs = getDeclaredMemberValuePairs(); + IMemberValuePairBinding[] otherMemberValuePairs = other.getDeclaredMemberValuePairs(); + if (memberValuePairs.length != otherMemberValuePairs.length) + return false; + for (int i = 0, length = memberValuePairs.length; i < length; i++) { + if (!memberValuePairs[i].isEqualTo(otherMemberValuePairs[i])) + return false; + } + return true; + } + + /* + * (non-Javadoc) + * @see org.eclipse.jdt.core.dom.IBinding#isRecovered() + */ + public boolean isRecovered() { + ReferenceBinding annotationType = this.binding.getAnnotationType(); + return annotationType == null || (annotationType.tagBits & TagBits.HasMissingType) != 0; } + + public boolean isSynthetic() { + return false; + } + + public String toString() { + ITypeBinding type = getAnnotationType(); + final StringBuffer buffer = new StringBuffer(); + buffer.append('@'); + if (type != null) + buffer.append(type.getName()); + buffer.append('('); + IMemberValuePairBinding[] pairs = getDeclaredMemberValuePairs(); + for (int i = 0, len = pairs.length; i < len; i++) { + if (i != 0) + buffer.append(", "); //$NON-NLS-1$ + buffer.append(pairs[i].toString()); + } + buffer.append(')'); + return buffer.toString(); + } + +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AnnotationTypeDeclaration.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AnnotationTypeDeclaration.java new file mode 100644 index 000000000..4924c2b9e --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AnnotationTypeDeclaration.java @@ -0,0 +1,272 @@ +/******************************************************************************* + * Copyright (c) 2004, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Annotation type declaration AST node type (added in JLS3 API). + * <pre> + * AnnotationTypeDeclaration: + * [ Javadoc ] { ExtendedModifier } <b>@</b> <b>interface</b> Identifier + * <b>{</b> { AnnotationTypeBodyDeclaration | <b>;</b> } <b>}</b> + * AnnotationTypeBodyDeclaration: + * AnnotationTypeMemberDeclaration + * FieldDeclaration + * TypeDeclaration + * EnumDeclaration + * AnnotationTypeDeclaration + * </pre> + * <p> + * The thing to note is that method declaration are replaced + * by annotation type member declarations in this context. + * </p> + * <p> + * When a Javadoc comment is present, the source + * range begins with the first character of the "/**" comment delimiter. + * When there is no Javadoc comment, the source range begins with the first + * character of the first modifier keyword (if modifiers), or the + * first character of the "@interface" (if no + * modifiers). The source range extends through the last character of the "}" + * token following the body declarations. + * </p> + * + * @since 3.1 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class AnnotationTypeDeclaration extends AbstractTypeDeclaration { + + /** + * The "javadoc" structural property of this node type. + */ + public static final ChildPropertyDescriptor JAVADOC_PROPERTY = + internalJavadocPropertyFactory(AnnotationTypeDeclaration.class); + + /** + * The "modifiers" structural property of this node type. + */ + public static final ChildListPropertyDescriptor MODIFIERS2_PROPERTY = + internalModifiers2PropertyFactory(AnnotationTypeDeclaration.class); + + /** + * The "name" structural property of this node type. + */ + public static final ChildPropertyDescriptor NAME_PROPERTY = + internalNamePropertyFactory(AnnotationTypeDeclaration.class); + + /** + * The "bodyDeclarations" structural property of this node type. + */ + public static final ChildListPropertyDescriptor BODY_DECLARATIONS_PROPERTY = + internalBodyDeclarationPropertyFactory(AnnotationTypeDeclaration.class); + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List properyList = new ArrayList(5); + createPropertyList(AnnotationTypeDeclaration.class, properyList); + addProperty(JAVADOC_PROPERTY, properyList); + addProperty(MODIFIERS2_PROPERTY, properyList); + addProperty(NAME_PROPERTY, properyList); + addProperty(BODY_DECLARATIONS_PROPERTY, properyList); + PROPERTY_DESCRIPTORS = reapPropertyList(properyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * Creates a new AST node for an annotation type declaration owned by the given + * AST. By default, the type declaration is for an annotation + * type of an unspecified, but legal, name; no modifiers; no javadoc; + * and an empty list of body declarations. + * <p> + * N.B. This constructor is package-private; all subclasses must be + * declared in the same package; clients are unable to declare + * additional subclasses. + * </p> + * + * @param ast the AST that is to own this node + */ + AnnotationTypeDeclaration(AST ast) { + super(ast); + unsupportedIn2(); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == JAVADOC_PROPERTY) { + if (get) { + return getJavadoc(); + } else { + setJavadoc((Javadoc) child); + return null; + } + } + if (property == NAME_PROPERTY) { + if (get) { + return getName(); + } else { + setName((SimpleName) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalGetChildListProperty(ChildListPropertyDescriptor property) { + if (property == MODIFIERS2_PROPERTY) { + return modifiers(); + } + if (property == BODY_DECLARATIONS_PROPERTY) { + return bodyDeclarations(); + } + // allow default implementation to flag the error + return super.internalGetChildListProperty(property); + } + + /* (omit javadoc for this method) + * Method declared on BodyDeclaration. + */ + final ChildPropertyDescriptor internalJavadocProperty() { + return JAVADOC_PROPERTY; + } + + /* (omit javadoc for this method) + * Method declared on BodyDeclaration. + */ + final ChildListPropertyDescriptor internalModifiers2Property() { + return MODIFIERS2_PROPERTY; + } + + /* (omit javadoc for this method) + * Method declared on BodyDeclaration. + */ + final SimplePropertyDescriptor internalModifiersProperty() { + // this property will not be asked for (node type did not exist in JLS2) + return null; + } + + /* (omit javadoc for this method) + * Method declared on AbstractTypeDeclaration. + */ + final ChildPropertyDescriptor internalNameProperty() { + return NAME_PROPERTY; + } + + /* (omit javadoc for this method) + * Method declared on AbstractTypeDeclaration. + */ + final ChildListPropertyDescriptor internalBodyDeclarationsProperty() { + return BODY_DECLARATIONS_PROPERTY; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return ANNOTATION_TYPE_DECLARATION; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + AnnotationTypeDeclaration result = new AnnotationTypeDeclaration(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setJavadoc( + (Javadoc) ASTNode.copySubtree(target, getJavadoc())); + result.modifiers().addAll(ASTNode.copySubtrees(target, modifiers())); + result.setName((SimpleName) getName().clone(target)); + result.bodyDeclarations().addAll(ASTNode.copySubtrees(target, bodyDeclarations())); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + acceptChild(visitor, getJavadoc()); + acceptChildren(visitor, this.modifiers); + acceptChild(visitor, getName()); + acceptChildren(visitor, this.bodyDeclarations); + } + visitor.endVisit(this); + } + + /* (omit javadoc for this method) + * Method declared on AsbtractTypeDeclaration. + */ + ITypeBinding internalResolveBinding() { + return this.ast.getBindingResolver().resolveType(this); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return super.memSize(); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.optionalDocComment == null ? 0 : getJavadoc().treeSize()) + + this.modifiers.listSize() + + (this.typeName == null ? 0 : getName().treeSize()) + + this.bodyDeclarations.listSize(); + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AnnotationTypeMemberDeclaration.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AnnotationTypeMemberDeclaration.java new file mode 100644 index 000000000..18238725d --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AnnotationTypeMemberDeclaration.java @@ -0,0 +1,417 @@ +/******************************************************************************* + * Copyright (c) 2004, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Annotation type member declaration AST node type (added in JLS3 API). + * <pre> + * AnnotationTypeMemberDeclaration: + * [ Javadoc ] { ExtendedModifier } + * Type Identifier <b>(</b> <b>)</b> [ <b>default</b> Expression ] <b>;</b> + * </pre> + * <p> + * Note that annotation type member declarations are only meaningful as + * elements of {@link AnnotationTypeDeclaration#bodyDeclarations()}. + * </p> + * <p> + * When a Javadoc comment is present, the source + * range begins with the first character of the "/**" comment delimiter. + * When there is no Javadoc comment, the source range begins with the first + * character of the first modifier keyword (if modifiers), + * or the first character of the member type (no modifiers). + * The source range extends through the last character of the + * ";" token. + * </p> + * + * @since 3.1 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class AnnotationTypeMemberDeclaration extends BodyDeclaration { + + /** + * The "javadoc" structural property of this node type. + */ + public static final ChildPropertyDescriptor JAVADOC_PROPERTY = + internalJavadocPropertyFactory(AnnotationTypeMemberDeclaration.class); + + /** + * The "modifiers" structural property of this node type. + */ + public static final ChildListPropertyDescriptor MODIFIERS2_PROPERTY = + internalModifiers2PropertyFactory(AnnotationTypeMemberDeclaration.class); + + /** + * The "name" structural property of this node type. + */ + public static final ChildPropertyDescriptor NAME_PROPERTY = + new ChildPropertyDescriptor(AnnotationTypeMemberDeclaration.class, "name", SimpleName.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "type" structural property of this node type. + */ + public static final ChildPropertyDescriptor TYPE_PROPERTY = + new ChildPropertyDescriptor(AnnotationTypeMemberDeclaration.class, "type", Type.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "default" structural property of this node type. + */ + public static final ChildPropertyDescriptor DEFAULT_PROPERTY = + new ChildPropertyDescriptor(AnnotationTypeMemberDeclaration.class, "default", Expression.class, OPTIONAL, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List properyList = new ArrayList(6); + createPropertyList(AnnotationTypeMemberDeclaration.class, properyList); + addProperty(JAVADOC_PROPERTY, properyList); + addProperty(MODIFIERS2_PROPERTY, properyList); + addProperty(NAME_PROPERTY, properyList); + addProperty(TYPE_PROPERTY, properyList); + addProperty(DEFAULT_PROPERTY, properyList); + PROPERTY_DESCRIPTORS = reapPropertyList(properyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The member name; lazily initialized; defaults to an unspecified, + * legal Java identifier. + */ + private SimpleName memberName = null; + + /** + * The member type; lazily initialized; defaults to int. + */ + private Type memberType = null; + + /** + * The optional default expression; <code>null</code> for none; defaults to none. + */ + private Expression optionalDefaultValue = null; + + /** + * Creates a new AST node for an annotation type member declaration owned + * by the given AST. By default, the declaration is for a member of an + * unspecified, but legal, name; no modifiers; no javadoc; + * an unspecified value type; and no default value. + * <p> + * N.B. This constructor is package-private; all subclasses must be + * declared in the same package; clients are unable to declare + * additional subclasses. + * </p> + * + * @param ast the AST that is to own this node + */ + AnnotationTypeMemberDeclaration(AST ast) { + super(ast); + unsupportedIn2(); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == JAVADOC_PROPERTY) { + if (get) { + return getJavadoc(); + } else { + setJavadoc((Javadoc) child); + return null; + } + } + if (property == NAME_PROPERTY) { + if (get) { + return getName(); + } else { + setName((SimpleName) child); + return null; + } + } + if (property == NAME_PROPERTY) { + if (get) { + return getName(); + } else { + setName((SimpleName) child); + return null; + } + } + if (property == TYPE_PROPERTY) { + if (get) { + return getType(); + } else { + setType((Type) child); + return null; + } + } + if (property == DEFAULT_PROPERTY) { + if (get) { + return getDefault(); + } else { + setDefault((Expression) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalGetChildListProperty(ChildListPropertyDescriptor property) { + if (property == MODIFIERS2_PROPERTY) { + return modifiers(); + } + // allow default implementation to flag the error + return super.internalGetChildListProperty(property); + } + + /* (omit javadoc for this method) + * Method declared on BodyDeclaration. + */ + final ChildPropertyDescriptor internalJavadocProperty() { + return JAVADOC_PROPERTY; + } + + /* (omit javadoc for this method) + * Method declared on BodyDeclaration. + */ + final ChildListPropertyDescriptor internalModifiers2Property() { + return MODIFIERS2_PROPERTY; + } + + /* (omit javadoc for this method) + * Method declared on BodyDeclaration. + */ + final SimplePropertyDescriptor internalModifiersProperty() { + // this property will not be asked for (node type did not exist in JLS2) + return null; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return ANNOTATION_TYPE_MEMBER_DECLARATION; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + AnnotationTypeMemberDeclaration result = new AnnotationTypeMemberDeclaration(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setJavadoc( + (Javadoc) ASTNode.copySubtree(target, getJavadoc())); + result.modifiers().addAll(ASTNode.copySubtrees(target, modifiers())); + result.setType((Type) ASTNode.copySubtree(target, getType())); + result.setName((SimpleName) getName().clone(target)); + result.setDefault((Expression) ASTNode.copySubtree(target, getDefault())); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + acceptChild(visitor, getJavadoc()); + acceptChildren(visitor, this.modifiers); + acceptChild(visitor, getType()); + acceptChild(visitor, getName()); + acceptChild(visitor, getDefault()); + } + visitor.endVisit(this); + } + + /** + * Returns the name of the annotation type member declared in this declaration. + * + * @return the member name node + */ + public SimpleName getName() { + if (this.memberName == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.memberName == null) { + preLazyInit(); + this.memberName = new SimpleName(this.ast); + postLazyInit(this.memberName, NAME_PROPERTY); + } + } + } + return this.memberName; + } + + /** + * Sets the name of the annotation type member declared in this declaration to the + * given name. + * + * @param memberName the new member name + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public void setName(SimpleName memberName) { + if (memberName == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.memberName; + preReplaceChild(oldChild, memberName, NAME_PROPERTY); + this.memberName = memberName; + postReplaceChild(oldChild, memberName, NAME_PROPERTY); + } + + /** + * Returns the type of the annotation type member declared in this + * declaration. + * + * @return the type of the member + */ + public Type getType() { + if (this.memberType == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.memberType == null) { + preLazyInit(); + this.memberType = this.ast.newPrimitiveType(PrimitiveType.INT); + postLazyInit(this.memberType, TYPE_PROPERTY); + } + } + } + return this.memberType; + } + + /** + * Sets the type of the annotation type member declared in this declaration + * to the given type. + * + * @param type the new member type + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public void setType(Type type) { + if (type == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.memberType; + preReplaceChild(oldChild, type, TYPE_PROPERTY); + this.memberType = type; + postReplaceChild(oldChild, type, TYPE_PROPERTY); + } + + /** + * Returns the default value of this annotation type member, or + * <code>null</code> if there is none. + * + * @return the expression node, or <code>null</code> if there is none + */ + public Expression getDefault() { + return this.optionalDefaultValue; + } + + /** + * Sets or clears the default value of this annotation type member. + * + * @param defaultValue the expression node, or <code>null</code> if + * there is none + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setDefault(Expression defaultValue) { + // a AnnotationTypeMemberDeclaration may occur inside an Expression - must check cycles + ASTNode oldChild = this.optionalDefaultValue; + preReplaceChild(oldChild, defaultValue, DEFAULT_PROPERTY); + this.optionalDefaultValue = defaultValue; + postReplaceChild(oldChild, defaultValue, DEFAULT_PROPERTY); + } + + /** + * Resolves and returns the binding for the annotation type member declared + * in this declaration. + * <p> + * Note that bindings are generally unavailable unless requested when the + * AST is being built. + * </p> + * + * @return the binding, or <code>null</code> if the binding cannot be + * resolved + */ + public IMethodBinding resolveBinding() { + return this.ast.getBindingResolver().resolveMember(this); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return super.memSize() + 3 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.optionalDocComment == null ? 0 : getJavadoc().treeSize()) + + this.modifiers.listSize() + + (this.memberName == null ? 0 : getName().treeSize()) + + (this.memberType == null ? 0 : getType().treeSize()) + + (this.optionalDefaultValue == null ? 0 : getDefault().treeSize()); + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AnonymousClassDeclaration.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AnonymousClassDeclaration.java new file mode 100644 index 000000000..97d407f22 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AnonymousClassDeclaration.java @@ -0,0 +1,190 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Anonymous class declaration AST node type. For JLS2, this type of node appears + * only as a child on a class instance creation expression. + * For JLS3, this type of node appears may also appear as the child of + * an enum constant declaration. + * + * <pre> + * AnonymousClassDeclaration: + * <b>{</b> ClassBodyDeclaration <b>}</b> + * </pre> + * + * @see ClassInstanceCreation + * @see EnumConstantDeclaration + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class AnonymousClassDeclaration extends ASTNode { + + /** + * The "bodyDeclarations" structural property of this node type. + * @since 3.0 + */ + public static final ChildListPropertyDescriptor BODY_DECLARATIONS_PROPERTY = + new ChildListPropertyDescriptor(AnonymousClassDeclaration.class, "bodyDeclarations", BodyDeclaration.class, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List properyList = new ArrayList(2); + createPropertyList(AnonymousClassDeclaration.class, properyList); + addProperty(BODY_DECLARATIONS_PROPERTY, properyList); + PROPERTY_DESCRIPTORS = reapPropertyList(properyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The body declarations (element type: <code>BodyDeclaration</code>). + * Defaults to none. + */ + private ASTNode.NodeList bodyDeclarations = + new ASTNode.NodeList(BODY_DECLARATIONS_PROPERTY); + + /** + * Creates a new AST node for an anonymous class declaration owned + * by the given AST. By default, the list of body declarations is empty. + * <p> + * N.B. This constructor is package-private; all subclasses must be + * declared in the same package; clients are unable to declare + * additional subclasses. + * </p> + * + * @param ast the AST that is to own this node + */ + AnonymousClassDeclaration(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalGetChildListProperty(ChildListPropertyDescriptor property) { + if (property == BODY_DECLARATIONS_PROPERTY) { + return bodyDeclarations(); + } + // allow default implementation to flag the error + return super.internalGetChildListProperty(property); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return ANONYMOUS_CLASS_DECLARATION; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + AnonymousClassDeclaration result = new AnonymousClassDeclaration(target); + result.setSourceRange(getStartPosition(), getLength()); + result.bodyDeclarations().addAll( + ASTNode.copySubtrees(target, bodyDeclarations())); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + acceptChildren(visitor, this.bodyDeclarations); + } + visitor.endVisit(this); + } + + /** + * Returns the live ordered list of body declarations of this + * anonymous class declaration. + * + * @return the live list of body declarations + * (element type: <code>BodyDeclaration</code>) + */ + public List bodyDeclarations() { + return this.bodyDeclarations; + } + + /** + * Resolves and returns the binding for the anonymous class declared in + * this declaration. + * <p> + * Note that bindings are generally unavailable unless requested when the + * AST is being built. + * </p> + * + * @return the binding, or <code>null</code> if the binding cannot be + * resolved + */ + public ITypeBinding resolveBinding() { + return this.ast.getBindingResolver().resolveType(this); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + // treat Code as free + return BASE_NODE_SIZE + 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + this.bodyDeclarations.listSize(); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ArrayAccess.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ArrayAccess.java new file mode 100644 index 000000000..58e02e0e3 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ArrayAccess.java @@ -0,0 +1,271 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Array access expression AST node type. + * + * <pre> + * ArrayAccess: + * Expression <b>[</b> Expression <b>]</b> + * </pre> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class ArrayAccess extends Expression { + + /** + * The "array" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor ARRAY_PROPERTY = + new ChildPropertyDescriptor(ArrayAccess.class, "array", Expression.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "index" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor INDEX_PROPERTY = + new ChildPropertyDescriptor(ArrayAccess.class, "index", Expression.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List properyList = new ArrayList(3); + createPropertyList(ArrayAccess.class, properyList); + addProperty(ARRAY_PROPERTY, properyList); + addProperty(INDEX_PROPERTY, properyList); + PROPERTY_DESCRIPTORS = reapPropertyList(properyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The array expression; lazily initialized; defaults to an unspecified, + * but legal, expression. + */ + private Expression arrayExpression = null; + + /** + * The index expression; lazily initialized; defaults to an unspecified, + * but legal, expression. + */ + private Expression indexExpression = null; + + /** + * Creates a new unparented array access expression node owned by the given + * AST. By default, the array and index expresssions are unspecified, + * but legal. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + ArrayAccess(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == ARRAY_PROPERTY) { + if (get) { + return getArray(); + } else { + setArray((Expression) child); + return null; + } + } + if (property == INDEX_PROPERTY) { + if (get) { + return getIndex(); + } else { + setIndex((Expression) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return ARRAY_ACCESS; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + ArrayAccess result = new ArrayAccess(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setArray((Expression) getArray().clone(target)); + result.setIndex((Expression) getIndex().clone(target)); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + acceptChild(visitor, getArray()); + acceptChild(visitor, getIndex()); + } + visitor.endVisit(this); + } + + /** + * Returns the array expression of this array access expression. + * + * @return the array expression node + */ + public Expression getArray() { + if (this.arrayExpression == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.arrayExpression == null) { + preLazyInit(); + this.arrayExpression = new SimpleName(this.ast); + postLazyInit(this.arrayExpression, ARRAY_PROPERTY); + } + } + } + return this.arrayExpression; + } + + /** + * Sets the array expression of this array access expression. + * + * @param expression the array expression node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setArray(Expression expression) { + if (expression == null) { + throw new IllegalArgumentException(); + } + // an ArrayAccess may occur inside an Expression + // must check cycles + ASTNode oldChild = this.arrayExpression; + preReplaceChild(oldChild, expression, ARRAY_PROPERTY); + this.arrayExpression = expression; + postReplaceChild(oldChild, expression, ARRAY_PROPERTY); + } + + /** + * Returns the index expression of this array access expression. + * + * @return the index expression node + */ + public Expression getIndex() { + if (this.indexExpression == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.indexExpression == null) { + preLazyInit(); + this.indexExpression = new SimpleName(this.ast); + postLazyInit(this.indexExpression, INDEX_PROPERTY); + } + } + } + return this.indexExpression; + } + + /** + * Sets the index expression of this array access expression. + * + * @param expression the index expression node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setIndex(Expression expression) { + if (expression == null) { + throw new IllegalArgumentException(); + } + // an ArrayAccess may occur inside an Expression + // must check cycles + ASTNode oldChild = this.indexExpression; + preReplaceChild(oldChild, expression, INDEX_PROPERTY); + this.indexExpression = expression; + postReplaceChild(oldChild, expression, INDEX_PROPERTY); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return BASE_NODE_SIZE + 2 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.arrayExpression == null ? 0 : getArray().treeSize()) + + (this.indexExpression == null ? 0 : getIndex().treeSize()); + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ArrayCreation.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ArrayCreation.java new file mode 100644 index 000000000..2a57be45c --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ArrayCreation.java @@ -0,0 +1,320 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Array creation expression AST node type. + * For JLS2: + * <pre> + * ArrayCreation: + * <b>new</b> PrimitiveType <b>[</b> Expression <b>]</b> { <b>[</b> Expression <b>]</b> } { <b>[</b> <b>]</b> } + * <b>new</b> TypeName <b>[</b> Expression <b>]</b> { <b>[</b> Expression <b>]</b> } { <b>[</b> <b>]</b> } + * <b>new</b> PrimitiveType <b>[</b> <b>]</b> { <b>[</b> <b>]</b> } ArrayInitializer + * <b>new</b> TypeName <b>[</b> <b>]</b> { <b>[</b> <b>]</b> } ArrayInitializer + * </pre> + * <p> + * The mapping from Java language syntax to AST nodes is as follows: + * <ul> + * <li>the type node is the array type of the creation expression, + * with one level of array per set of square brackets,</li> + * <li>the dimension expressions are collected into the <code>dimensions</code> + * list.</li> + * </ul> + * </p> + * For JLS3, type arguments are added: + * <pre> + * ArrayCreation: + * <b>new</b> PrimitiveType <b>[</b> Expression <b>]</b> { <b>[</b> Expression <b>]</b> } { <b>[</b> <b>]</b> } + * <b>new</b> TypeName [ <b><</b> Type { <b>,</b> Type } <b>></b> ] + * <b>[</b> Expression <b>]</b> { <b>[</b> Expression <b>]</b> } { <b>[</b> <b>]</b> } + * <b>new</b> PrimitiveType <b>[</b> <b>]</b> { <b>[</b> <b>]</b> } ArrayInitializer + * <b>new</b> TypeName [ <b><</b> Type { <b>,</b> Type } <b>></b> ] + * <b>[</b> <b>]</b> { <b>[</b> <b>]</b> } ArrayInitializer + * </pre> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class ArrayCreation extends Expression { + + /** + * The "type" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor TYPE_PROPERTY = + new ChildPropertyDescriptor(ArrayCreation.class, "type", ArrayType.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "dimensions" structural property of this node type. + * @since 3.0 + */ + public static final ChildListPropertyDescriptor DIMENSIONS_PROPERTY = + new ChildListPropertyDescriptor(ArrayCreation.class, "dimensions", Expression.class, CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "initializer" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor INITIALIZER_PROPERTY = + new ChildPropertyDescriptor(ArrayCreation.class, "initializer", ArrayInitializer.class, OPTIONAL, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List properyList = new ArrayList(4); + createPropertyList(ArrayCreation.class, properyList); + addProperty(TYPE_PROPERTY, properyList); + addProperty(DIMENSIONS_PROPERTY, properyList); + addProperty(INITIALIZER_PROPERTY, properyList); + PROPERTY_DESCRIPTORS = reapPropertyList(properyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The array type; lazily initialized; defaults to a unspecified, + * legal array type. + */ + private ArrayType arrayType = null; + + /** + * The list of dimension expressions (element type: + * <code>Expression</code>). Defaults to an empty list. + */ + private ASTNode.NodeList dimensions = + new ASTNode.NodeList(DIMENSIONS_PROPERTY); + + /** + * The optional array initializer, or <code>null</code> if none; + * defaults to none. + */ + private ArrayInitializer optionalInitializer = null; + + /** + * Creates a new AST node for an array creation expression owned by the + * given AST. By default, the array type is an unspecified 1-dimensional + * array, the list of dimensions is empty, and there is no array + * initializer. + * + * @param ast the AST that is to own this node + */ + ArrayCreation(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == INITIALIZER_PROPERTY) { + if (get) { + return getInitializer(); + } else { + setInitializer((ArrayInitializer) child); + return null; + } + } + if (property == TYPE_PROPERTY) { + if (get) { + return getType(); + } else { + setType((ArrayType) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalGetChildListProperty(ChildListPropertyDescriptor property) { + if (property == DIMENSIONS_PROPERTY) { + return dimensions(); + } + // allow default implementation to flag the error + return super.internalGetChildListProperty(property); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return ARRAY_CREATION; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + ArrayCreation result = new ArrayCreation(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setType((ArrayType) getType().clone(target)); + result.dimensions().addAll(ASTNode.copySubtrees(target, dimensions())); + result.setInitializer( + (ArrayInitializer) ASTNode.copySubtree(target, getInitializer())); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + acceptChild(visitor, getType()); + acceptChildren(visitor, this.dimensions); + acceptChild(visitor, getInitializer()); + } + visitor.endVisit(this); + } + + /** + * Returns the array type in this array creation expression. + * + * @return the array type + */ + public ArrayType getType() { + if (this.arrayType == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.arrayType == null) { + preLazyInit(); + this.arrayType = this.ast.newArrayType( + this.ast.newPrimitiveType(PrimitiveType.INT)); + postLazyInit(this.arrayType, TYPE_PROPERTY); + } + } + } + return this.arrayType; + } + + /** + * Sets the array type in this array creation expression. + * + * @param type the new array type + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public void setType(ArrayType type) { + if (type == null) { + throw new IllegalArgumentException(); + } + // an ArrayCreation cannot occur inside a ArrayType - cycles not possible + ASTNode oldChild = this.arrayType; + preReplaceChild(oldChild, type, TYPE_PROPERTY); + this.arrayType = type; + postReplaceChild(oldChild, type, TYPE_PROPERTY); + } + + /** + * Returns the live ordered list of dimension expressions in this array + * initializer. + * + * @return the live list of dimension expressions + * (element type: <code>Expression</code>) + */ + public List dimensions() { + return this.dimensions; + } + + /** + * Returns the array initializer of this array creation expression, or + * <code>null</code> if there is none. + * + * @return the array initializer node, or <code>null</code> if + * there is none + */ + public ArrayInitializer getInitializer() { + return this.optionalInitializer; + } + + /** + * Sets or clears the array initializer of this array creation expression. + * + * @param initializer the array initializer node, or <code>null</code> + * if there is none + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setInitializer(ArrayInitializer initializer) { + // an ArrayCreation may occur inside an ArrayInitializer + // must check cycles + ASTNode oldChild = this.optionalInitializer; + preReplaceChild(oldChild, initializer, INITIALIZER_PROPERTY); + this.optionalInitializer = initializer; + postReplaceChild(oldChild, initializer, INITIALIZER_PROPERTY); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return BASE_NODE_SIZE + 3 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + int size = memSize() + + (this.arrayType == null ? 0 : getType().treeSize()) + + (this.optionalInitializer == null ? 0 : getInitializer().treeSize()) + + this.dimensions.listSize(); + return size; + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ArrayInitializer.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ArrayInitializer.java new file mode 100644 index 000000000..342faf063 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ArrayInitializer.java @@ -0,0 +1,161 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Array initializer AST node type. + * + * <pre> + * ArrayInitializer: + * <b>{</b> [ Expression { <b>,</b> Expression} [ <b>,</b> ]] <b>}</b> + * </pre> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class ArrayInitializer extends Expression { + + /** + * The "expressions" structural property of this node type. + * @since 3.0 + */ + public static final ChildListPropertyDescriptor EXPRESSIONS_PROPERTY = + new ChildListPropertyDescriptor(ArrayInitializer.class, "expressions", Expression.class, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List properyList = new ArrayList(2); + createPropertyList(ArrayInitializer.class, properyList); + addProperty(EXPRESSIONS_PROPERTY, properyList); + PROPERTY_DESCRIPTORS = reapPropertyList(properyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The list of expressions (element type: + * <code>Expression</code>). Defaults to an empty list. + */ + private ASTNode.NodeList expressions = + new ASTNode.NodeList(EXPRESSIONS_PROPERTY); + + /** + * Creates a new AST node for an array initializer owned by the + * given AST. By default, the list of expressions is empty. + * + * @param ast the AST that is to own this node + */ + ArrayInitializer(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalGetChildListProperty(ChildListPropertyDescriptor property) { + if (property == EXPRESSIONS_PROPERTY) { + return expressions(); + } + // allow default implementation to flag the error + return super.internalGetChildListProperty(property); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return ARRAY_INITIALIZER; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + ArrayInitializer result = new ArrayInitializer(target); + result.setSourceRange(getStartPosition(), getLength()); + result.expressions().addAll(ASTNode.copySubtrees(target, expressions())); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + acceptChildren(visitor, this.expressions); + } + visitor.endVisit(this); + } + + /** + * Returns the live ordered list of expressions in this array initializer. + * + * @return the live list of expressions + * (element type: <code>Expression</code>) + */ + public List expressions() { + return this.expressions; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return BASE_NODE_SIZE + 1 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return memSize() + this.expressions.listSize(); + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ArrayType.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ArrayType.java new file mode 100644 index 000000000..25f8d9301 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ArrayType.java @@ -0,0 +1,241 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Type node for an array type. + * <p> + * Array types are expressed in a recursive manner, one dimension at a time. + * </p> + * <pre> + * ArrayType: + * Type <b>[</b> <b>]</b> + * </pre> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class ArrayType extends Type { + + /** + * The "componentType" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor COMPONENT_TYPE_PROPERTY = + new ChildPropertyDescriptor(ArrayType.class, "componentType", Type.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List properyList = new ArrayList(2); + createPropertyList(ArrayType.class, properyList); + addProperty(COMPONENT_TYPE_PROPERTY, properyList); + PROPERTY_DESCRIPTORS = reapPropertyList(properyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The component type; lazily initialized; defaults to a simple type with + * an unspecfied, but legal, name. + */ + private Type componentType = null; + + /** + * Creates a new unparented node for an array type owned by the given AST. + * By default, a 1-dimensional array of an unspecified simple type. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + ArrayType(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == COMPONENT_TYPE_PROPERTY) { + if (get) { + return getComponentType(); + } else { + setComponentType((Type) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return ARRAY_TYPE; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + ArrayType result = new ArrayType(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setComponentType((Type) getComponentType().clone(target)); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + acceptChild(visitor, getComponentType()); + } + visitor.endVisit(this); + } + + /** + * Returns the component type of this array type. The component type + * may be another array type. + * + * @return the component type node + */ + public Type getComponentType() { + if (this.componentType == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.componentType == null) { + preLazyInit(); + this.componentType = new SimpleType(this.ast); + postLazyInit(this.componentType, COMPONENT_TYPE_PROPERTY); + } + } + } + return this.componentType; + } + + /** + * Sets the component type of this array type. The component type + * may be another array type. + * + * @param componentType the component type + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setComponentType(Type componentType) { + if (componentType == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.componentType; + preReplaceChild(oldChild, componentType, COMPONENT_TYPE_PROPERTY); + this.componentType = componentType; + postReplaceChild(oldChild, componentType, COMPONENT_TYPE_PROPERTY); + } + + /** + * Returns the element type of this array type. The element type is + * never an array type. + * <p> + * This is a convenience method that descends a chain of nested array types + * until it reaches a non-array type. + * </p> + * + * @return the component type node + */ + public Type getElementType() { + Type t = getComponentType(); + while (t.isArrayType()) { + t = ((ArrayType) t).getComponentType(); + } + return t; + } + + /** + * Returns the number of dimensions in this array type. + * <p> + * This is a convenience method that descends a chain of nested array types + * until it reaches a non-array type. + * </p> + * + * @return the number of dimensions (always positive) + */ + public int getDimensions() { + Type t = getComponentType(); + int dimensions = 1; // always include this array type + while (t.isArrayType()) { + dimensions++; + t = ((ArrayType) t).getComponentType(); + } + return dimensions; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return BASE_NODE_SIZE + 1 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.componentType == null ? 0 : getComponentType().treeSize()); + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AssertStatement.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AssertStatement.java new file mode 100644 index 000000000..c7720f9a4 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AssertStatement.java @@ -0,0 +1,262 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Assert statement AST node type. + * + * <pre> + * AssertStatement: + * <b>assert</b> Expression [ <b>:</b> Expression ] <b>;</b> + * </pre> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class AssertStatement extends Statement { + + /** + * The "expression" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor EXPRESSION_PROPERTY = + new ChildPropertyDescriptor(AssertStatement.class, "expression", Expression.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "message" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor MESSAGE_PROPERTY = + new ChildPropertyDescriptor(AssertStatement.class, "message", Expression.class, OPTIONAL, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List properyList = new ArrayList(3); + createPropertyList(AssertStatement.class, properyList); + addProperty(EXPRESSION_PROPERTY, properyList); + addProperty(MESSAGE_PROPERTY, properyList); + PROPERTY_DESCRIPTORS = reapPropertyList(properyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The expression; lazily initialized; defaults to a unspecified, but legal, + * expression. + */ + private Expression expression = null; + + /** + * The message expression; <code>null</code> for none; defaults to none. + */ + private Expression optionalMessageExpression = null; + + /** + * Creates a new unparented assert statement node owned by the given + * AST. By default, the assert statement has an unspecified, but legal, + * expression, and not message expression. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + AssertStatement(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == EXPRESSION_PROPERTY) { + if (get) { + return getExpression(); + } else { + setExpression((Expression) child); + return null; + } + } + if (property == MESSAGE_PROPERTY) { + if (get) { + return getMessage(); + } else { + setMessage((Expression) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return ASSERT_STATEMENT; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + AssertStatement result = new AssertStatement(target); + result.setSourceRange(getStartPosition(), getLength()); + result.copyLeadingComment(this); + result.setExpression( + (Expression) ASTNode.copySubtree(target, getExpression())); + result.setMessage( + (Expression) ASTNode.copySubtree(target, getMessage())); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + acceptChild(visitor, getExpression()); + acceptChild(visitor, getMessage()); + } + visitor.endVisit(this); + } + + /** + * Returns the first expression of this assert statement. + * + * @return the expression node + */ + public Expression getExpression() { + if (this.expression == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.expression == null) { + preLazyInit(); + this.expression = new SimpleName(this.ast); + postLazyInit(this.expression, EXPRESSION_PROPERTY); + } + } + } + return this.expression; + } + + /** + * Sets the first expression of this assert statement. + * + * @param expression the new expression node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setExpression(Expression expression) { + if (expression == null) { + throw new IllegalArgumentException(); + } + // an AssertStatement may occur inside an Expression - must check cycles + ASTNode oldChild = this.expression; + preReplaceChild(oldChild, expression, EXPRESSION_PROPERTY); + this.expression = expression; + postReplaceChild(oldChild, expression, EXPRESSION_PROPERTY); + } + + /** + * Returns the message expression of this assert statement, or + * <code>null</code> if there is none. + * + * @return the message expression node, or <code>null</code> if there + * is none + */ + public Expression getMessage() { + return this.optionalMessageExpression; + } + + /** + * Sets or clears the message expression of this assert statement. + * + * @param expression the message expression node, or <code>null</code> if + * there is none + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setMessage(Expression expression) { + // an AsertStatement may occur inside an Expression - must check cycles + ASTNode oldChild = this.optionalMessageExpression; + preReplaceChild(oldChild, expression, MESSAGE_PROPERTY); + this.optionalMessageExpression = expression; + postReplaceChild(oldChild, expression, MESSAGE_PROPERTY); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return super.memSize() + 2 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.expression == null ? 0 : getExpression().treeSize()) + + (this.optionalMessageExpression == null ? 0 : getMessage().treeSize()); + + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Assignment.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Assignment.java new file mode 100644 index 000000000..411c94641 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Assignment.java @@ -0,0 +1,441 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Assignment expression AST node type. + * + * <pre> + * Assignment: + * Expression AssignmentOperator Expression + * </pre> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class Assignment extends Expression { + + /** + * Assignment operators (typesafe enumeration). + * <pre> + * AssignmentOperator:<code> + * <b>=</b> ASSIGN + * <b>+=</b> PLUS_ASSIGN + * <b>-=</b> MINUS_ASSIGN + * <b>*=</b> TIMES_ASSIGN + * <b>/=</b> DIVIDE_ASSIGN + * <b>&=</b> BIT_AND_ASSIGN + * <b>|=</b> BIT_OR_ASSIGN + * <b>^=</b> BIT_XOR_ASSIGN + * <b>%=</b> REMAINDER_ASSIGN + * <b><<=</b> LEFT_SHIFT_ASSIGN + * <b>>>=</b> RIGHT_SHIFT_SIGNED_ASSIGN + * <b>>>>=</b> RIGHT_SHIFT_UNSIGNED_ASSIGN</code> + * </pre> + */ + public static class Operator { + + /** + * The name of the operator + */ + private String op; + + /** + * Creates a new assignment operator with the given name. + * <p> + * Note: this constructor is private. The only instances + * ever created are the ones for the standard operators. + * </p> + * + * @param op the character sequence for the operator + */ + private Operator(String op) { + this.op = op; + } + + /** + * Returns the character sequence for the operator. + * + * @return the character sequence for the operator + */ + public String toString() { + return this.op; + } + + /** = operator. */ + public static final Operator ASSIGN = new Operator("=");//$NON-NLS-1$ + /** += operator. */ + public static final Operator PLUS_ASSIGN = new Operator("+=");//$NON-NLS-1$ + /** -= operator. */ + public static final Operator MINUS_ASSIGN = new Operator("-=");//$NON-NLS-1$ + /** *= operator. */ + public static final Operator TIMES_ASSIGN = new Operator("*=");//$NON-NLS-1$ + /** /= operator. */ + public static final Operator DIVIDE_ASSIGN = new Operator("/=");//$NON-NLS-1$ + /** &= operator. */ + public static final Operator BIT_AND_ASSIGN = new Operator("&=");//$NON-NLS-1$ + /** |= operator. */ + public static final Operator BIT_OR_ASSIGN = new Operator("|=");//$NON-NLS-1$ + /** ^= operator. */ + public static final Operator BIT_XOR_ASSIGN = new Operator("^=");//$NON-NLS-1$ + /** %= operator. */ + public static final Operator REMAINDER_ASSIGN = new Operator("%=");//$NON-NLS-1$ + /** <<== operator. */ + public static final Operator LEFT_SHIFT_ASSIGN = + new Operator("<<=");//$NON-NLS-1$ + /** >>= operator. */ + public static final Operator RIGHT_SHIFT_SIGNED_ASSIGN = + new Operator(">>=");//$NON-NLS-1$ + /** >>>= operator. */ + public static final Operator RIGHT_SHIFT_UNSIGNED_ASSIGN = + new Operator(">>>=");//$NON-NLS-1$ + + /** + * Returns the assignment operator corresponding to the given string, + * or <code>null</code> if none. + * <p> + * <code>toOperator</code> is the converse of <code>toString</code>: + * that is, <code>Operator.toOperator(op.toString()) == op</code> for all + * operators <code>op</code>. + * </p> + * + * @param token the character sequence for the operator + * @return the assignment operator, or <code>null</code> if none + */ + public static Operator toOperator(String token) { + return (Operator) CODES.get(token); + } + + /** + * Map from token to operator (key type: <code>String</code>; + * value type: <code>Operator</code>). + */ + private static final Map CODES; + static { + CODES = new HashMap(20); + Operator[] ops = { + ASSIGN, + PLUS_ASSIGN, + MINUS_ASSIGN, + TIMES_ASSIGN, + DIVIDE_ASSIGN, + BIT_AND_ASSIGN, + BIT_OR_ASSIGN, + BIT_XOR_ASSIGN, + REMAINDER_ASSIGN, + LEFT_SHIFT_ASSIGN, + RIGHT_SHIFT_SIGNED_ASSIGN, + RIGHT_SHIFT_UNSIGNED_ASSIGN + }; + for (int i = 0; i < ops.length; i++) { + CODES.put(ops[i].toString(), ops[i]); + } + } + } + + /** + * The "leftHandSide" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor LEFT_HAND_SIDE_PROPERTY = + new ChildPropertyDescriptor(Assignment.class, "leftHandSide", Expression.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "operator" structural property of this node type. + * @since 3.0 + */ + public static final SimplePropertyDescriptor OPERATOR_PROPERTY = + new SimplePropertyDescriptor(Assignment.class, "operator", Assignment.Operator.class, MANDATORY); //$NON-NLS-1$ + + /** + * The "rightHandSide" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor RIGHT_HAND_SIDE_PROPERTY = + new ChildPropertyDescriptor(Assignment.class, "rightHandSide", Expression.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List properyList = new ArrayList(4); + createPropertyList(Assignment.class, properyList); + addProperty(LEFT_HAND_SIDE_PROPERTY, properyList); + addProperty(OPERATOR_PROPERTY, properyList); + addProperty(RIGHT_HAND_SIDE_PROPERTY, properyList); + PROPERTY_DESCRIPTORS = reapPropertyList(properyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The assignment operator; defaults to Assignment.Operator.ASSIGN + */ + private Assignment.Operator assignmentOperator = Assignment.Operator.ASSIGN; + + /** + * The left hand side; lazily initialized; defaults to an unspecified, + * but legal, simple name. + */ + private Expression leftHandSide = null; + + /** + * The right hand side; lazily initialized; defaults to an unspecified, + * but legal, simple name. + */ + private Expression rightHandSide = null; + + /** + * Creates a new AST node for an assignment expression owned by the given + * AST. By default, the node has an assignment operator, and unspecified + * left and right hand sides. + * + * @param ast the AST that is to own this node + */ + Assignment(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final Object internalGetSetObjectProperty(SimplePropertyDescriptor property, boolean get, Object value) { + if (property == OPERATOR_PROPERTY) { + if (get) { + return getOperator(); + } else { + setOperator((Operator) value); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetObjectProperty(property, get, value); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == LEFT_HAND_SIDE_PROPERTY) { + if (get) { + return getLeftHandSide(); + } else { + setLeftHandSide((Expression) child); + return null; + } + } + if (property == RIGHT_HAND_SIDE_PROPERTY) { + if (get) { + return getRightHandSide(); + } else { + setRightHandSide((Expression) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return ASSIGNMENT; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + Assignment result = new Assignment(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setOperator(getOperator()); + result.setLeftHandSide((Expression) getLeftHandSide().clone(target)); + result.setRightHandSide((Expression) getRightHandSide().clone(target)); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + acceptChild(visitor, getLeftHandSide()); + acceptChild(visitor, getRightHandSide()); + } + visitor.endVisit(this); + } + + /** + * Returns the operator of this assignment expression. + * + * @return the assignment operator + */ + public Assignment.Operator getOperator() { + return this.assignmentOperator; + } + + /** + * Sets the operator of this assignment expression. + * + * @param assignmentOperator the assignment operator + * @exception IllegalArgumentException if the argument is incorrect + */ + public void setOperator(Assignment.Operator assignmentOperator) { + if (assignmentOperator == null) { + throw new IllegalArgumentException(); + } + preValueChange(OPERATOR_PROPERTY); + this.assignmentOperator = assignmentOperator; + postValueChange(OPERATOR_PROPERTY); + } + + /** + * Returns the left hand side of this assignment expression. + * + * @return the left hand side node + */ + public Expression getLeftHandSide() { + if (this.leftHandSide == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.leftHandSide == null) { + preLazyInit(); + this.leftHandSide= new SimpleName(this.ast); + postLazyInit(this.leftHandSide, LEFT_HAND_SIDE_PROPERTY); + } + } + } + return this.leftHandSide; + } + + /** + * Sets the left hand side of this assignment expression. + * + * @param expression the left hand side node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setLeftHandSide(Expression expression) { + if (expression == null) { + throw new IllegalArgumentException(); + } + // an Assignment may occur inside a Expression - must check cycles + ASTNode oldChild = this.leftHandSide; + preReplaceChild(oldChild, expression, LEFT_HAND_SIDE_PROPERTY); + this.leftHandSide = expression; + postReplaceChild(oldChild, expression, LEFT_HAND_SIDE_PROPERTY); + } + + /** + * Returns the right hand side of this assignment expression. + * + * @return the right hand side node + */ + public Expression getRightHandSide() { + if (this.rightHandSide == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.rightHandSide == null) { + preLazyInit(); + this.rightHandSide= new SimpleName(this.ast); + postLazyInit(this.rightHandSide, RIGHT_HAND_SIDE_PROPERTY); + } + } + } + return this.rightHandSide; + } + + /** + * Sets the right hand side of this assignment expression. + * + * @param expression the right hand side node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setRightHandSide(Expression expression) { + if (expression == null) { + throw new IllegalArgumentException(); + } + // an Assignment may occur inside a Expression - must check cycles + ASTNode oldChild = this.rightHandSide; + preReplaceChild(oldChild, expression, RIGHT_HAND_SIDE_PROPERTY); + this.rightHandSide = expression; + postReplaceChild(oldChild, expression, RIGHT_HAND_SIDE_PROPERTY); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + // treat Code as free + return BASE_NODE_SIZE + 3 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.leftHandSide == null ? 0 : getLeftHandSide().treeSize()) + + (this.rightHandSide == null ? 0 : getRightHandSide().treeSize()); + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/BaseCallMessageSend.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/BaseCallMessageSend.java new file mode 100644 index 000000000..94c0ee59c --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/BaseCallMessageSend.java @@ -0,0 +1,273 @@ +/********************************************************************** + * This file is part of "Object Teams Development Tooling"-Software + * + * Copyright 2004, 2006 Fraunhofer Gesellschaft, Munich, Germany, + * for its Fraunhofer Institute for Computer Architecture and Software + * Technology (FIRST), Berlin, Germany and Technical University Berlin, + * Germany. + * + * 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 + * $Id: BaseCallMessageSend.java 23416 2010-02-03 19:59:31Z stephan $ + * + * Please visit http://www.eclipse.org/objectteams for updates and contact. + * + * Contributors: + * Fraunhofer FIRST - Initial API and implementation + * Technical University Berlin - Initial API and implementation + **********************************************************************/ +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * NEW for OTDT + * + * BaseCallMessageSend represents a 'base call' + * inside a role method with 'callin' modifier (OTJLD §4.3), + * e.g. + * <code>base.myRoleMethod(arg1, arg2)</code> + * + * Contained AST elements: + * a selector name (<code>SimpleName</code>), e.g. <code>myRoleMethod<code>. + * a List of argument expressions (<code>Expression</code>). + * + * @author mkr + * @version $Id: BaseCallMessageSend.java 23416 2010-02-03 19:59:31Z stephan $ + */ +public class BaseCallMessageSend extends Expression +{ + /** + * The "name" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor NAME_PROPERTY = + new ChildPropertyDescriptor(BaseCallMessageSend.class, + "name",//$NON-NLS-1$ + SimpleName.class, + MANDATORY, + NO_CYCLE_RISK); + + /** + * The "arguments" structural property of this node type. + * @since 3.0 + */ + public static final ChildListPropertyDescriptor ARGUMENTS_PROPERTY = + new ChildListPropertyDescriptor(BaseCallMessageSend.class, + "arguments",//$NON-NLS-1$ + Expression.class, + CYCLE_RISK); + + + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static + { + List propertyList = new ArrayList(3); + createPropertyList(BaseCallMessageSend.class, propertyList); + addProperty(NAME_PROPERTY, propertyList); + addProperty(ARGUMENTS_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + */ + public static List propertyDescriptors(int apiLevel) + { + return PROPERTY_DESCRIPTORS; + } + + /** + * The method name; lazily initialized; + */ + private SimpleName _methodName = null; + + /** + * The list of argument expressions (element type: + * <code>Expression</code>). Defaults to an empty list. + */ + private ASTNode.NodeList _arguments = + new ASTNode.NodeList(ARGUMENTS_PROPERTY); + + /** + * Creates a new AST node for a tsuper expression owned by the given AST. + * By default, there is no qualifier. + * + * @param ast the AST that is to own this node + */ + BaseCallMessageSend(AST ast) + { + super(ast); + } + + final List internalStructuralPropertiesForType(int apiLevel) + { + return propertyDescriptors(apiLevel); + } + + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, + boolean get, + ASTNode child) + { + + if (property == NAME_PROPERTY) + { + if (get) { + return getName(); + } + else + { + setName((SimpleName) child); + return null; + } + } + + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + final List internalGetChildListProperty(ChildListPropertyDescriptor property) + { + if (property == ARGUMENTS_PROPERTY) + { + return getArguments(); + } + + // allow default implementation to flag the error + return super.internalGetChildListProperty(property); + } + + final int getNodeType0() + { + return BASE_CALL_MESSAGE_SEND; + } + + @SuppressWarnings("unchecked") + ASTNode clone0(AST target) + { + BaseCallMessageSend result = new BaseCallMessageSend(target); + result.setSourceRange(this.getStartPosition(), this.getLength()); + result.setName((SimpleName)_methodName.clone(target)); + result.getArguments().addAll(ASTNode.copySubtrees(target, _arguments)); + return result; + } + + final boolean subtreeMatch0(ASTMatcher matcher, Object other) + { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + void accept0(ASTVisitor visitor) + { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + acceptChild(visitor, _methodName); + acceptChildren(visitor, _arguments); + } + visitor.endVisit(this); + } + + + /** + * Returns the name of the method invoked in this expression. + * + * @return the method name node + */ + public SimpleName getName() + { + if (_methodName == null) + { + // lazy init must be thread-safe for readers + synchronized (this) + { + if (_methodName == null) + { + preLazyInit(); + _methodName = new SimpleName(this.ast); + postLazyInit(_methodName, NAME_PROPERTY); + } + } + } + return _methodName; + } + + /** + * Sets the name of the method invoked in this expression to the + * given name. + * + * @param name the new method name + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public void setName(SimpleName name) + { + if (name == null) + { + throw new IllegalArgumentException(); + } + ASTNode oldChild = _methodName; + preReplaceChild(oldChild, name, NAME_PROPERTY); + _methodName = name; + postReplaceChild(oldChild, name, NAME_PROPERTY); + } + + /** + * Returns the ordered list of argument expressions in this + * base call method send expression. + * + * @return the live list of argument expressions + * (element type: <code>Expression</code>) + */ + public List getArguments() + { + return _arguments; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() + { + return BASE_NODE_SIZE + 4 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() + { + return + memSize() + + (_methodName == null ? 0 : _methodName.treeSize()) + + (_arguments == null ? 0 : _arguments.listSize()); + } + + public IMethodBinding resolveMethodBinding() + { + return this.ast.getBindingResolver().resolveMethod(this); + } + + + +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/BaseConstructorInvocation.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/BaseConstructorInvocation.java new file mode 100644 index 000000000..25f4c5126 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/BaseConstructorInvocation.java @@ -0,0 +1,184 @@ +/********************************************************************** + * This file is part of "Object Teams Development Tooling"-Software + * + * Copyright 2004, 2006 Fraunhofer Gesellschaft, Munich, Germany, + * for its Fraunhofer Institute for Computer Architecture and Software + * Technology (FIRST), Berlin, Germany and Technical University Berlin, + * Germany. + * + * 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 + * $Id: BaseConstructorInvocation.java 23416 2010-02-03 19:59:31Z stephan $ + * + * Please visit http://www.eclipse.org/objectteams for updates and contact. + * + * Contributors: + * Fraunhofer FIRST - Initial API and implementation + * Technical University Berlin - Initial API and implementation + **********************************************************************/ +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * NEW for OTDT + * + * BaseConstructorMessageSend represents a 'base call' to a constructor of the + * role's base class (OTJLD §2.4.2), + * e.g. <code>base();</code> or <code>base(arg1, arg2);</code>. + * + * Contained AST elements: + * a list of argument expressions (<code>Expression</code>). + * + * Locations in source code: + * This node can only be used within role constructor bodies, i.e. it appears in + * ordinary <code>ExpressionStatement</code>s only. + * + * Contrary to org.eclipse.jdt.internal.compiler.ast.BaseConstructorMessageSend + * this is not an assignment. In the compiler ast + * "base(args)" is translated to "_OT$base = new BaseClass(args);". + * In the dom ast we just need "base(args);". + * + * @author mkr + * @version $Id: BaseConstructorInvocation.java 23416 2010-02-03 19:59:31Z stephan $ + */ +public class BaseConstructorInvocation extends Statement +{ + /** + * The "arguments" structural property of this node type. + * @since 3.0 + */ + public static final ChildListPropertyDescriptor ARGUMENTS_PROPERTY = + new ChildListPropertyDescriptor(BaseConstructorInvocation.class, "arguments", Expression.class, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static + { + List propertyList = new ArrayList(2); + createPropertyList(BaseConstructorInvocation.class, propertyList); + addProperty(ARGUMENTS_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + */ + public static List propertyDescriptors(int apiLevel) + { + return PROPERTY_DESCRIPTORS; + } + + /** + * The list of argument expressions (element type: + * <code>Expression</code>). Defaults to an empty list. + */ + private ASTNode.NodeList _arguments = + new ASTNode.NodeList(ARGUMENTS_PROPERTY); + + /** + * Creates a new AST node for a base expression owned by the given AST. + * By default, there is no qualifier. + * + * @param ast the AST that is to own this node + */ + BaseConstructorInvocation(AST ast) + { + super(ast); + } + + /** + * Returns the live ordered list of argument expressions in this + * base constructor invocation expression. + * + * @return the live list of argument expressions + * (element type: <code>Expression</code>) + */ + public List getArguments() + { + return _arguments; + } + + final List internalStructuralPropertiesForType(int apiLevel) + { + return propertyDescriptors(apiLevel); + } + + final List internalGetChildListProperty(ChildListPropertyDescriptor property) + { + if (property == ARGUMENTS_PROPERTY) + { + return getArguments(); + } + + // allow default implementation to flag the error + return super.internalGetChildListProperty(property); + } + + final int getNodeType0() + { + return BASE_CONSTRUCTOR_INVOCATION; + } + + @SuppressWarnings("unchecked") + ASTNode clone0(AST target) + { + BaseConstructorInvocation result = new BaseConstructorInvocation(target); + result.setSourceRange(this.getStartPosition(), this.getLength()); + result.getArguments().addAll(ASTNode.copySubtrees(target, getArguments())); + + return result; + } + + final boolean subtreeMatch0(ASTMatcher matcher, Object other) + { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + void accept0(ASTVisitor visitor) + { + boolean visitChildren = visitor.visit(this); + + if (visitChildren) + { + // visit children in normal left to right reading order + acceptChildren(visitor, _arguments); + } + visitor.endVisit(this); + } + + + int memSize() + { + // treat Operator as free + return BASE_NODE_SIZE + 1 * 4; + } + + int treeSize() + { + return memSize() + (_arguments == null + ? 0 + : _arguments.listSize()); + } + + public IMethodBinding resolveConstructorBinding() { + return this.ast.getBindingResolver().resolveConstructor(this); + } + + +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/BindingComparator.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/BindingComparator.java new file mode 100644 index 000000000..27aff86ea --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/BindingComparator.java @@ -0,0 +1,346 @@ +/******************************************************************************* + * Copyright (c) 2004, 2008 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: + * IBM Corporation - initial API and implementation + * Technical University Berlin - extended API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.dom; + +import java.util.HashSet; + +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import org.eclipse.jdt.internal.compiler.lookup.Binding; +import org.eclipse.jdt.internal.compiler.lookup.CaptureBinding; +import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers; +import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; +import org.eclipse.jdt.internal.compiler.lookup.ImportBinding; +import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding; +import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; +import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding; +import org.eclipse.jdt.internal.compiler.lookup.VariableBinding; +import org.eclipse.jdt.internal.compiler.lookup.WildcardBinding; + +/** + * Internal helper class for comparing bindings. + * + * @since 3.1 + */ +class BindingComparator { + /** + * @param bindings + * @param otherBindings + * @return true if both parameters are equals, false otherwise + */ + static boolean isEqual(TypeVariableBinding[] bindings, TypeVariableBinding[] otherBindings) { + if (bindings == null) { + return otherBindings == null; + } + if (otherBindings == null) { + return false; + } + int length = bindings.length; + int otherLength = otherBindings.length; + if (length != otherLength) { + return false; + } + for (int i = 0; i < length; i++) { + TypeVariableBinding typeVariableBinding = bindings[i]; + TypeVariableBinding typeVariableBinding2 = otherBindings[i]; + if (!isEqual(typeVariableBinding, typeVariableBinding2)) { + return false; + } + } + return true; + } + + /** + * @param declaringElement + * @param declaringElement2 + * @return true if both parameters are equals, false otherwise + */ + static boolean isEqual(Binding declaringElement, Binding declaringElement2, HashSet visitedTypes) { + if (declaringElement instanceof org.eclipse.jdt.internal.compiler.lookup.TypeBinding) { + if (!(declaringElement2 instanceof org.eclipse.jdt.internal.compiler.lookup.TypeBinding)){ + return false; + } + return isEqual((org.eclipse.jdt.internal.compiler.lookup.TypeBinding) declaringElement, + (org.eclipse.jdt.internal.compiler.lookup.TypeBinding) declaringElement2, + visitedTypes); + } else if (declaringElement instanceof org.eclipse.jdt.internal.compiler.lookup.MethodBinding) { + if (!(declaringElement2 instanceof org.eclipse.jdt.internal.compiler.lookup.MethodBinding)) { + return false; + } + return isEqual((org.eclipse.jdt.internal.compiler.lookup.MethodBinding) declaringElement, + (org.eclipse.jdt.internal.compiler.lookup.MethodBinding) declaringElement2, + visitedTypes); + } else if (declaringElement instanceof VariableBinding) { + if (!(declaringElement2 instanceof VariableBinding)) { + return false; + } + return isEqual((VariableBinding) declaringElement, + (VariableBinding) declaringElement2); + } else if (declaringElement instanceof org.eclipse.jdt.internal.compiler.lookup.PackageBinding) { + if (!(declaringElement2 instanceof org.eclipse.jdt.internal.compiler.lookup.PackageBinding)) { + return false; + } + org.eclipse.jdt.internal.compiler.lookup.PackageBinding packageBinding = (org.eclipse.jdt.internal.compiler.lookup.PackageBinding) declaringElement; + org.eclipse.jdt.internal.compiler.lookup.PackageBinding packageBinding2 = (org.eclipse.jdt.internal.compiler.lookup.PackageBinding) declaringElement2; + return CharOperation.equals(packageBinding.compoundName, packageBinding2.compoundName); + } else if (declaringElement instanceof ImportBinding) { + if (!(declaringElement2 instanceof ImportBinding)) { + return false; + } + ImportBinding importBinding = (ImportBinding) declaringElement; + ImportBinding importBinding2 = (ImportBinding) declaringElement2; + return importBinding.isStatic() == importBinding2.isStatic() + && importBinding.onDemand == importBinding2.onDemand + && CharOperation.equals(importBinding.compoundName, importBinding2.compoundName); + } + return false; + } + + static boolean isEqual(org.eclipse.jdt.internal.compiler.lookup.MethodBinding methodBinding, + org.eclipse.jdt.internal.compiler.lookup.MethodBinding methodBinding2) { + return isEqual(methodBinding, methodBinding2, new HashSet()); + } + + static boolean isEqual(org.eclipse.jdt.internal.compiler.lookup.MethodBinding methodBinding, + org.eclipse.jdt.internal.compiler.lookup.MethodBinding methodBinding2, + HashSet visitedTypes) { + if (methodBinding == null) { + return methodBinding2 == null; + } + if (methodBinding2 == null) return false; + return CharOperation.equals(methodBinding.selector, methodBinding2.selector) + && isEqual(methodBinding.returnType, methodBinding2.returnType, visitedTypes) + && isEqual(methodBinding.thrownExceptions, methodBinding2.thrownExceptions, visitedTypes) + && isEqual(methodBinding.declaringClass, methodBinding2.declaringClass, visitedTypes) + && isEqual(methodBinding.typeVariables, methodBinding2.typeVariables, visitedTypes) + && isEqual(methodBinding.parameters, methodBinding2.parameters, visitedTypes); + } + + static boolean isEqual(org.eclipse.objectteams.otdt.internal.core.compiler.lookup.CallinCalloutBinding mapping, + org.eclipse.objectteams.otdt.internal.core.compiler.lookup.CallinCalloutBinding mapping2) + { + return isEqual(mapping, mapping2, new HashSet()); + } + + static boolean isEqual(org.eclipse.objectteams.otdt.internal.core.compiler.lookup.CallinCalloutBinding mapping, + org.eclipse.objectteams.otdt.internal.core.compiler.lookup.CallinCalloutBinding mapping2, + HashSet visitedTypes) + { + if (mapping == null) { + return mapping2 == null; + } + if (mapping2 == null) return false; + if (mapping.name != null || mapping2.name != null) { + if (mapping.name == null || mapping2.name == null) return false; + if (!CharOperation.equals(mapping.name, mapping2.name)) return false; + } + if (mapping.isCallin() != mapping2.isCallin()) return false; + if (!isEqual(mapping._roleMethodBinding, mapping2._roleMethodBinding)) return false; + if (mapping.callinModifier != mapping2.callinModifier) return false; + if (mapping.calloutModifier != mapping2.calloutModifier) return false; + org.eclipse.jdt.internal.compiler.lookup.MethodBinding[] baseMethods = mapping._baseMethods; + org.eclipse.jdt.internal.compiler.lookup.MethodBinding[] baseMethods2 = mapping2._baseMethods; + if (baseMethods.length != baseMethods2.length) return false; + for (int i = 0; i < baseMethods.length; i++) + if (!isEqual(baseMethods[i], baseMethods2[i])) return false; + return true; + } + + static boolean isEqual(VariableBinding variableBinding, VariableBinding variableBinding2) { + return (variableBinding.modifiers & ExtraCompilerModifiers.AccJustFlag) == (variableBinding2.modifiers & ExtraCompilerModifiers.AccJustFlag) + && CharOperation.equals(variableBinding.name, variableBinding2.name) + && isEqual(variableBinding.type, variableBinding2.type) + && (variableBinding.id == variableBinding2.id); + } + + static boolean isEqual(FieldBinding fieldBinding, FieldBinding fieldBinding2) { + HashSet visitedTypes = new HashSet(); + return (fieldBinding.modifiers & ExtraCompilerModifiers.AccJustFlag) == (fieldBinding2.modifiers & ExtraCompilerModifiers.AccJustFlag) + && CharOperation.equals(fieldBinding.name, fieldBinding2.name) + && isEqual(fieldBinding.type, fieldBinding2.type, visitedTypes) + && isEqual(fieldBinding.declaringClass, fieldBinding2.declaringClass, visitedTypes); + } + + /** + * @param bindings + * @param otherBindings + * @return true if both parameters are equals, false otherwise + */ + static boolean isEqual(org.eclipse.jdt.internal.compiler.lookup.TypeBinding[] bindings, org.eclipse.jdt.internal.compiler.lookup.TypeBinding[] otherBindings) { + return isEqual(bindings, otherBindings, new HashSet()); + } + /** + * @param bindings + * @param otherBindings + * @return true if both parameters are equals, false otherwise + */ + static boolean isEqual(org.eclipse.jdt.internal.compiler.lookup.TypeBinding[] bindings, org.eclipse.jdt.internal.compiler.lookup.TypeBinding[] otherBindings, HashSet visitedTypes) { + if (bindings == null) { + return otherBindings == null; + } + if (otherBindings == null) { + return false; + } + int length = bindings.length; + int otherLength = otherBindings.length; + if (length != otherLength) { + return false; + } + for (int i = 0; i < length; i++) { + if (!isEqual(bindings[i], otherBindings[i], visitedTypes)) { + return false; + } + } + return true; + } + static boolean isEqual(org.eclipse.jdt.internal.compiler.lookup.TypeBinding typeBinding, org.eclipse.jdt.internal.compiler.lookup.TypeBinding typeBinding2, HashSet visitedTypes) { + if (typeBinding == typeBinding2) + return true; + if (typeBinding == null || typeBinding2 == null) + return false; + +// TODO(SH): Should this method use AccOTTypeJustFlag instead of AccJustFlag? + + switch (typeBinding.kind()) { + case Binding.BASE_TYPE : + if (!typeBinding2.isBaseType()) { + return false; + } + return typeBinding.id == typeBinding2.id; + + case Binding.ARRAY_TYPE : + if (!typeBinding2.isArrayType()) { + return false; + } + return typeBinding.dimensions() == typeBinding2.dimensions() + && isEqual(typeBinding.leafComponentType(), typeBinding2.leafComponentType(), visitedTypes); + + case Binding.PARAMETERIZED_TYPE : + if (!typeBinding2.isParameterizedType()) { + return false; + } + ParameterizedTypeBinding parameterizedTypeBinding = (ParameterizedTypeBinding) typeBinding; + ParameterizedTypeBinding parameterizedTypeBinding2 = (ParameterizedTypeBinding) typeBinding2; + return CharOperation.equals(parameterizedTypeBinding.compoundName, parameterizedTypeBinding2.compoundName) + && (parameterizedTypeBinding.modifiers & (ExtraCompilerModifiers.AccJustFlag | ClassFileConstants.AccInterface | ClassFileConstants.AccEnum | ClassFileConstants.AccAnnotation)) + == (parameterizedTypeBinding2.modifiers & (ExtraCompilerModifiers.AccJustFlag | ClassFileConstants.AccInterface | ClassFileConstants.AccEnum | ClassFileConstants.AccAnnotation)) + && isEqual(parameterizedTypeBinding.arguments, parameterizedTypeBinding2.arguments, visitedTypes) + && isEqual(parameterizedTypeBinding.enclosingType(), parameterizedTypeBinding2.enclosingType(), visitedTypes); + + case Binding.WILDCARD_TYPE : + if (typeBinding2.kind() != Binding.WILDCARD_TYPE) { + return false; + } + WildcardBinding wildcardBinding = (WildcardBinding) typeBinding; + WildcardBinding wildcardBinding2 = (WildcardBinding) typeBinding2; + return isEqual(wildcardBinding.bound, wildcardBinding2.bound, visitedTypes) + && wildcardBinding.boundKind == wildcardBinding2.boundKind; + + case Binding.INTERSECTION_TYPE: + if (typeBinding2.kind() != Binding.INTERSECTION_TYPE) { + return false; + } + WildcardBinding intersectionBinding = (WildcardBinding) typeBinding; + WildcardBinding intersectionBinding2 = (WildcardBinding) typeBinding2; + return isEqual(intersectionBinding.bound, intersectionBinding2.bound, visitedTypes) + && isEqual(intersectionBinding.otherBounds, intersectionBinding2.otherBounds, visitedTypes); + + case Binding.TYPE_PARAMETER : + if (!(typeBinding2.isTypeVariable())) { + return false; + } + if (typeBinding.isCapture()) { + if (!(typeBinding2.isCapture())) { + return false; + } + CaptureBinding captureBinding = (CaptureBinding) typeBinding; + CaptureBinding captureBinding2 = (CaptureBinding) typeBinding2; + if (captureBinding.position == captureBinding2.position) { + if (visitedTypes.contains(typeBinding)) return true; + visitedTypes.add(typeBinding); + + return isEqual(captureBinding.wildcard, captureBinding2.wildcard, visitedTypes) + && isEqual(captureBinding.sourceType, captureBinding2.sourceType, visitedTypes); + } + return false; + } + TypeVariableBinding typeVariableBinding = (TypeVariableBinding) typeBinding; + TypeVariableBinding typeVariableBinding2 = (TypeVariableBinding) typeBinding2; + if (CharOperation.equals(typeVariableBinding.sourceName, typeVariableBinding2.sourceName)) { + if (visitedTypes.contains(typeBinding)) return true; + visitedTypes.add(typeBinding); + + return isEqual(typeVariableBinding.declaringElement, typeVariableBinding2.declaringElement, visitedTypes) + && isEqual(typeVariableBinding.superclass(), typeVariableBinding2.superclass(), visitedTypes) + && isEqual(typeVariableBinding.superInterfaces(), typeVariableBinding2.superInterfaces(), visitedTypes); + } + return false; + case Binding.GENERIC_TYPE : + if (!typeBinding2.isGenericType()) { + return false; + } + ReferenceBinding referenceBinding = (ReferenceBinding) typeBinding; + ReferenceBinding referenceBinding2 = (ReferenceBinding) typeBinding2; + return CharOperation.equals(referenceBinding.compoundName, referenceBinding2.compoundName) + && (referenceBinding.modifiers & (ExtraCompilerModifiers.AccJustFlag | ClassFileConstants.AccInterface | ClassFileConstants.AccEnum | ClassFileConstants.AccAnnotation)) + == (referenceBinding2.modifiers & (ExtraCompilerModifiers.AccJustFlag | ClassFileConstants.AccInterface | ClassFileConstants.AccEnum | ClassFileConstants.AccAnnotation)) + && isEqual(referenceBinding.typeVariables(), referenceBinding2.typeVariables(), visitedTypes) + && isEqual(referenceBinding.enclosingType(), referenceBinding2.enclosingType(), visitedTypes); + + case Binding.RAW_TYPE : + default : + if (!(typeBinding2 instanceof ReferenceBinding)) { + return false; + } +//{ObjectTeams: avoid confusion between class/ifc parts of a role: +/* orig: + referenceBinding = (ReferenceBinding) typeBinding; + referenceBinding2 = (ReferenceBinding) typeBinding2; + :giro */ + referenceBinding = ((ReferenceBinding) typeBinding).getRealType(); + referenceBinding2 = ((ReferenceBinding) typeBinding2).getRealType(); +// SH} + char[] constantPoolName = referenceBinding.constantPoolName(); + char[] constantPoolName2 = referenceBinding2.constantPoolName(); + // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=116833 + if (constantPoolName == null) { + if (constantPoolName2 != null) { + return false; + } + if (!CharOperation.equals(referenceBinding.computeUniqueKey(), referenceBinding2.computeUniqueKey())) { + return false; + } + } else { + if (constantPoolName2 == null) { + return false; + } + if (!CharOperation.equals(constantPoolName, constantPoolName2)) { + return false; + } + } + return CharOperation.equals(referenceBinding.compoundName, referenceBinding2.compoundName) + && (!referenceBinding2.isGenericType()) + && (referenceBinding.isRawType() == referenceBinding2.isRawType()) + && ((referenceBinding.modifiers & ~ClassFileConstants.AccSuper) & (ExtraCompilerModifiers.AccJustFlag | ClassFileConstants.AccInterface | ClassFileConstants.AccEnum | ClassFileConstants.AccAnnotation)) + == ((referenceBinding2.modifiers & ~ClassFileConstants.AccSuper) & (ExtraCompilerModifiers.AccJustFlag | ClassFileConstants.AccInterface | ClassFileConstants.AccEnum | ClassFileConstants.AccAnnotation)) + && isEqual(referenceBinding.enclosingType(), referenceBinding2.enclosingType(), visitedTypes); + } + } + /** + * @param typeBinding + * @param typeBinding2 + * @return true if both parameters are equals, false otherwise + */ + static boolean isEqual(org.eclipse.jdt.internal.compiler.lookup.TypeBinding typeBinding, org.eclipse.jdt.internal.compiler.lookup.TypeBinding typeBinding2) { + return isEqual(typeBinding, typeBinding2, new HashSet()); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/BindingResolver.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/BindingResolver.java new file mode 100644 index 000000000..0b2424805 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/BindingResolver.java @@ -0,0 +1,1049 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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 + * $Id: BindingResolver.java 23405 2010-02-03 17:02:18Z stephan $ + * + * Contributors: + * IBM Corporation - initial API and implementation + * Fraunhofer FIRST - extended API and implementation + * Technical University Berlin - extended API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import org.eclipse.jdt.core.WorkingCopyOwner; +import org.eclipse.jdt.internal.compiler.lookup.BlockScope; +import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope; +import org.eclipse.jdt.internal.compiler.lookup.ElementValuePair; +import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment; + +/** + * A binding resolver is an internal mechanism for figuring out the binding + * for a major declaration, type, or name reference. This also handles + * the creation and mapping between annotations and the ast nodes that define them. + * <p> + * The default implementation serves as the default binding resolver + * that does no resolving whatsoever. Internal subclasses do all the real work. + * </p> + * + * @see AST#getBindingResolver + */ +class BindingResolver { + + /** + * Creates a binding resolver. + */ + BindingResolver() { + // default implementation: do nothing + } + + /** + * Finds the corresponding AST node from which the given binding originated. + * Returns <code>null</code> if the binding does not correspond to any node + * in the compilation unit. + * <p> + * The following table indicates the expected node type for the various + * different kinds of bindings: + * <ul> + * <li></li> + * <li>package - a <code>PackageDeclaration</code></li> + * <li>class or interface - a <code>TypeDeclaration</code> or a + * <code>ClassInstanceCreation</code> (for anonymous classes) </li> + * <li>primitive type - none</li> + * <li>array type - none</li> + * <li>field - a <code>VariableDeclarationFragment</code> in a + * <code>FieldDeclaration</code> </li> + * <li>local variable - a <code>SingleVariableDeclaration</code>, or + * a <code>VariableDeclarationFragment</code> in a + * <code>VariableDeclarationStatement</code> or + * <code>VariableDeclarationExpression</code></li> + * <li>method - a <code>MethodDeclaration</code> </li> + * <li>constructor - a <code>MethodDeclaration</code> </li> + * <li>annotation type - an <code>AnnotationTypeDeclaration</code> + * <li>annotation type member - an <code>AnnotationTypeMemberDeclaration</code> + * </ul> + * </p> + * <p> + * The implementation of <code>CompilationUnit.findDeclaringNode</code> + * forwards to this method. + * </p> + * <p> + * The default implementation of this method returns <code>null</code>. + * Subclasses may reimplement. + * </p> + * + * @param binding the binding + * @return the corresponding node where the bindings is declared, + * or <code>null</code> if none + */ + ASTNode findDeclaringNode(IBinding binding) { + return null; + } + + /** + * Finds the corresponding AST node from which the given binding key originated. + * + * The default implementation of this method returns <code>null</code>. + * Subclasses may reimplement. + * </p> + * + * @param bindingKey the binding key + * @return the corresponding node where the bindings is declared, + * or <code>null</code> if none + */ + ASTNode findDeclaringNode(String bindingKey) { + return null; + } + + /** + * Finds the corresponding AST node from which the given annotation instance originated. + * + * The default implementation of this method returns <code>null</code>. + * Subclasses may reimplement. + * </p> + * + * @param instance the dom annotation + * @return the corresponding node where the bindings is declared, + * or <code>null</code> if none + */ + ASTNode findDeclaringNode(IAnnotationBinding instance) { + return null; + } + + /** + * Allows the user to get information about the given old/new pair of + * AST nodes. + * <p> + * The default implementation of this method does nothing. + * Subclasses may reimplement. + * </p> + * + * @param currentNode the new node + * @return org.eclipse.jdt.internal.compiler.ast.ASTNode + */ + org.eclipse.jdt.internal.compiler.ast.ASTNode getCorrespondingNode(ASTNode currentNode) { + return null; + } + + /** + * Returns the new method binding corresponding to the given old method binding. + * <p> + * The default implementation of this method returns <code>null</code>. + * Subclasses may reimplement. + * </p> + * + * @param methodBinding the old method binding + * @return the new method binding + */ + IMethodBinding getMethodBinding(org.eclipse.jdt.internal.compiler.lookup.MethodBinding methodBinding) { + return null; + } + +//{ObjectTeams: new retrieval: + IMethodMappingBinding getMethodMappingBinding(org.eclipse.objectteams.otdt.internal.core.compiler.lookup.CallinCalloutBinding callbinding) { + return null; + } +// SH} + /** + * Returns the new member value pair binding corresponding to the given old value pair binding. + * <p> + * The default implementation of this method returns <code>null</code>. + * Subclasses may reimplement. + * </p> + * + * @param valuePair the old value pair binding + * @return the new member value pair binding + */ + IMemberValuePairBinding getMemberValuePairBinding(ElementValuePair valuePair) { + return null; + } + + /** + * Returns the new package binding corresponding to the given old package binding. + * <p> + * The default implementation of this method returns <code>null</code>. + * Subclasses may reimplement. + * </p> + * + * @param packageBinding the old package binding + * @return the new package binding + */ + IPackageBinding getPackageBinding(org.eclipse.jdt.internal.compiler.lookup.PackageBinding packageBinding) { + return null; + } + + /** + * Returns the new type binding corresponding to the given old type binding. + * <p> + * The default implementation of this method returns <code>null</code>. + * Subclasses may reimplement. + * </p> + * + * @param referenceBinding the old type binding + * @return the new type binding + */ + ITypeBinding getTypeBinding(org.eclipse.jdt.internal.compiler.lookup.TypeBinding referenceBinding) { + return null; + } + + + /** + * Returns the new type binding corresponding to the given variableDeclaration. + * This is used for recovered binding only. + * <p> + * The default implementation of this method returns <code>null</code>. + * Subclasses may reimplement. + * </p> + * + * @param variableDeclaration the given variable declaration + * @return the new type binding + */ + ITypeBinding getTypeBinding(VariableDeclaration variableDeclaration) { + return null; + } + + /** + * Returns the new type binding corresponding to the given type. This is used for recovered binding + * only. + * <p> + * The default implementation of this method returns <code>null</code>. + * Subclasses may reimplement. + * </p> + * + * @param type the given type + * @return the new type binding + */ + ITypeBinding getTypeBinding(Type type) { + return null; + } + + /** + * Returns the new type binding corresponding to the given recovered type binding. + * <p> + * The default implementation of this method returns <code>null</code>. + * Subclasses may reimplement. + * </p> + * + * @param recoveredTypeBinding the recovered type binding + * @param dimensions the dimensions to add the to given type binding dimensions + * @return the new type binding + */ + ITypeBinding getTypeBinding(RecoveredTypeBinding recoveredTypeBinding, int dimensions) { + return null; + } + + /** + * Returns the new variable binding corresponding to the given old variable binding. + * <p> + * The default implementation of this method returns <code>null</code>. + * Subclasses may reimplement. + * </p> + * + * @param binding the old variable binding + * @return the new variable binding + */ + IVariableBinding getVariableBinding(org.eclipse.jdt.internal.compiler.lookup.VariableBinding binding) { + return null; + } + + /** + * Return the working copy owner for the receiver. + * <p> + * The default implementation of this method returns <code>null</code>. + * Subclasses may reimplement. + * </p> + * @return the working copy owner for the receiver + */ + public WorkingCopyOwner getWorkingCopyOwner() { + return null; + } + + /** + * Return the new annotation corresponding to the given old annotation + * <p> + * The default implementation of this method returns <code>null</code> + * Subclasses may reimplement. + * </p> + * + * @param instance the old annotation + * @return the new DOM annotation + */ + IAnnotationBinding getAnnotationInstance(org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding instance) { + return null; + } + + boolean isResolvedTypeInferredFromExpectedType(MethodInvocation methodInvocation) { + return false; + } + + boolean isResolvedTypeInferredFromExpectedType(SuperMethodInvocation methodInvocation) { + return false; + } + + /** + * Returns the compiler lookup environment used by this binding resolver. + * Returns <code>null</code> if none. + * + * @return the lookup environment used by this resolver, or <code>null</code> if none. + */ + LookupEnvironment lookupEnvironment() { + return null; + } + + /** + * This method is used to record the scope and its corresponding node. + * <p> + * The default implementation of this method does nothing. + * Subclasses may reimplement. + * </p> + * @param astNode + */ + void recordScope(ASTNode astNode, BlockScope blockScope) { + // default implementation: do nothing + } + + /** + * Returns whether this expression node is the site of a boxing + * conversion (JLS3 5.1.7). This information is available only + * when bindings are requested when the AST is being built. + * + * @return <code>true</code> if this expression is the site of a + * boxing conversion, or <code>false</code> if either no boxing conversion + * is involved or if bindings were not requested when the AST was created + * @since 3.1 + */ + boolean resolveBoxing(Expression expression) { + return false; + } + + /** + * Returns whether this expression node is the site of an unboxing + * conversion (JLS3 5.1.8). This information is available only + * when bindings are requested when the AST is being built. + * + * @return <code>true</code> if this expression is the site of an + * unboxing conversion, or <code>false</code> if either no unboxing + * conversion is involved or if bindings were not requested when the + * AST was created + * @since 3.1 + */ + boolean resolveUnboxing(Expression expression) { + return false; + } + + /** + * Resolves and returns the compile-time constant expression value as + * specified in JLS2 15.28, if this expression has one. Constant expression + * values are unavailable unless bindings are requested when the AST is + * being built. If the type of the value is a primitive type, the result + * is the boxed equivalent (i.e., int returned as an <code>Integer</code>); + * if the type of the value is <code>String</code>, the result is the string + * itself. If the expression does not have a compile-time constant expression + * value, the result is <code>null</code>. + * <p> + * Resolving constant expressions takes into account the value of simple + * and qualified names that refer to constant variables (JLS2 4.12.4). + * </p> + * <p> + * Note 1: enum constants are not considered constant expressions either. + * The result is always <code>null</code> for these. + * </p> + * <p> + * Note 2: Compile-time constant expressions cannot denote <code>null</code>. + * So technically {@link NullLiteral} nodes are not constant expressions. + * The result is <code>null</code> for these nonetheless. + * </p> + * + * @return the constant expression value, or <code>null</code> if this + * expression has no constant expression value or if bindings were not + * requested when the AST was created + * @since 3.1 + */ + Object resolveConstantExpressionValue(Expression expression) { + return null; + } + + /** + * Resolves and returns the binding for the constructor being invoked. + * <p> + * The implementation of + * <code>ClassInstanceCreation.resolveConstructor</code> + * forwards to this method. Which constructor is invoked is often a function + * of the context in which the expression node is embedded as well as + * the expression subtree itself. + * </p> + * <p> + * The default implementation of this method returns <code>null</code>. + * Subclasses may reimplement. + * </p> + * + * @param expression the expression of interest + * @return the binding for the constructor being invoked, or + * <code>null</code> if no binding is available + */ + IMethodBinding resolveConstructor(ClassInstanceCreation expression) { + return null; + } + + /** + * Resolves and returns the binding for the constructor being invoked. + * <p> + * The implementation of + * <code>ConstructorInvocation.resolveConstructor</code> + * forwards to this method. Which constructor is invoked is often a function + * of the context in which the expression node is embedded as well as + * the expression subtree itself. + * </p> + * <p> + * The default implementation of this method returns <code>null</code>. + * Subclasses may reimplement. + * </p> + * + * @param expression the expression of interest + * @return the binding for the constructor being invoked, or + * <code>null</code> if no binding is available + */ + IMethodBinding resolveConstructor(ConstructorInvocation expression) { + return null; + } + /** + * Resolves and returns the binding for the constructor being invoked. + * <p> + * The implementation of + * <code>ConstructorInvocation.resolveConstructor</code> + * forwards to this method. Which constructor is invoked is often a function + * of the context in which the expression node is embedded as well as + * the expression subtree itself. + * </p> + * <p> + * The default implementation of this method returns <code>null</code>. + * Subclasses may reimplement. + * </p> + * + * @param enumConstantDeclaration the enum constant declaration of interest + * @return the binding for the constructor being invoked, or + * <code>null</code> if no binding is available + */ + IMethodBinding resolveConstructor(EnumConstantDeclaration enumConstantDeclaration) { + return null; + } + /** + * Resolves and returns the binding for the constructor being invoked. + * <p> + * The implementation of + * <code>SuperConstructorInvocation.resolveConstructor</code> + * forwards to this method. Which constructor is invoked is often a function + * of the context in which the expression node is embedded as well as + * the expression subtree itself. + * </p> + * <p> + * The default implementation of this method returns <code>null</code>. + * Subclasses may reimplement. + * </p> + * + * @param expression the expression of interest + * @return the binding for the constructor being invoked, or + * <code>null</code> if no binding is available + */ + IMethodBinding resolveConstructor(SuperConstructorInvocation expression) { + return null; + } + /** + * Resolves the type of the given expression and returns the type binding + * for it. + * <p> + * The implementation of <code>Expression.resolveTypeBinding</code> + * forwards to this method. The result is often a function of the context + * in which the expression node is embedded as well as the expression + * subtree itself. + * </p> + * <p> + * The default implementation of this method returns <code>null</code>. + * Subclasses may reimplement. + * </p> + * + * @param expression the expression whose type is of interest + * @return the binding for the type of the given expression, or + * <code>null</code> if no binding is available + */ + ITypeBinding resolveExpressionType(Expression expression) { + return null; + } + + /** + * Resolves the given field access and returns the binding for it. + * <p> + * The implementation of <code>FieldAccess.resolveFieldBinding</code> + * forwards to this method. How the field resolves is often a function of + * the context in which the field access node is embedded as well as + * the field access subtree itself. + * </p> + * <p> + * The default implementation of this method returns <code>null</code>. + * Subclasses may reimplement. + * </p> + * + * @param fieldAccess the field access of interest + * @return the binding for the given field access, or + * <code>null</code> if no binding is available + */ + IVariableBinding resolveField(FieldAccess fieldAccess) { + return null; + } + + /** + * Resolves the given super field access and returns the binding for it. + * <p> + * The implementation of <code>SuperFieldAccess.resolveFieldBinding</code> + * forwards to this method. How the field resolves is often a function of + * the context in which the super field access node is embedded as well as + * the super field access subtree itself. + * </p> + * <p> + * The default implementation of this method returns <code>null</code>. + * Subclasses may reimplement. + * </p> + * + * @param fieldAccess the super field access of interest + * @return the binding for the given field access, or + * <code>null</code> if no binding is available + */ + IVariableBinding resolveField(SuperFieldAccess fieldAccess) { + return null; + } + + /** + * Resolves the given import declaration and returns the binding for it. + * <p> + * The implementation of <code>ImportDeclaration.resolveBinding</code> + * forwards to this method. + * </p> + * <p> + * The default implementation of this method returns <code>null</code>. + * Subclasses may reimplement. + * </p> + * + * @param importDeclaration the import declaration of interest + * @return the binding for the given package declaration, or + * the package binding (for on-demand imports) or type binding + * (for single-type imports), or <code>null</code> if no binding is + * available + */ + IBinding resolveImport(ImportDeclaration importDeclaration) { + return null; + } + + /** + * Resolves the given annotation type declaration and returns the binding + * for it. + * <p> + * The implementation of <code>AnnotationTypeMemberDeclaration.resolveBinding</code> + * forwards to this method. How the declaration resolves is often a + * function of the context in which the declaration node is embedded as well + * as the declaration subtree itself. + * </p> + * <p> + * The default implementation of this method returns <code>null</code>. + * Subclasses may reimplement. + * </p> + * + * @param member the annotation type member declaration of interest + * @return the binding for the given annotation type member declaration, or <code>null</code> + * if no binding is available + * @since 3.0 + */ + IMethodBinding resolveMember(AnnotationTypeMemberDeclaration member) { + return null; + } + + /** + * Resolves the given method declaration and returns the binding for it. + * <p> + * The implementation of <code>MethodDeclaration.resolveBinding</code> + * forwards to this method. How the method resolves is often a function of + * the context in which the method declaration node is embedded as well as + * the method declaration subtree itself. + * </p> + * <p> + * The default implementation of this method returns <code>null</code>. + * Subclasses may reimplement. + * </p> + * + * @param method the method or constructor declaration of interest + * @return the binding for the given method declaration, or + * <code>null</code> if no binding is available + */ + IMethodBinding resolveMethod(MethodDeclaration method) { + return null; + } + + /** + * Resolves the given method invocation and returns the binding for it. + * <p> + * The implementation of <code>MethodInvocation.resolveMethodBinding</code> + * forwards to this method. How the method resolves is often a function of + * the context in which the method invocation node is embedded as well as + * the method invocation subtree itself. + * </p> + * <p> + * The default implementation of this method returns <code>null</code>. + * Subclasses may reimplement. + * </p> + * + * @param method the method invocation of interest + * @return the binding for the given method invocation, or + * <code>null</code> if no binding is available + */ + IMethodBinding resolveMethod(MethodInvocation method) { + return null; + } + +//{ObjectTeams: resolve bindings for OT-specific nodes + + IMethodBinding resolveConstructor(BaseConstructorInvocation constructor) + { + return null; + } + + IMethodBinding resolveConstructor(TSuperConstructorInvocation constructor) + { + return null; + } + + + IMethodBinding resolveMethod(BaseCallMessageSend method) + { + return null; + } + + + IMethodBinding resolveMethod(MethodSpec method) + { + return null; + } + + IMethodBinding resolveMethod(TSuperMessageSend method) + { + return null; + } + + IMethodMappingBinding resolveMethodMapping(AbstractMethodMappingDeclaration mapping) + { + return null; + } + + IVariableBinding resolveVariable(FieldAccessSpec field) + { + return null; + } +//mkr} + + /** + * Resolves the given method invocation and returns the binding for it. + * <p> + * The implementation of <code>MethodInvocation.resolveMethodBinding</code> + * forwards to this method. How the method resolves is often a function of + * the context in which the method invocation node is embedded as well as + * the method invocation subtree itself. + * </p> + * <p> + * The default implementation of this method returns <code>null</code>. + * Subclasses may reimplement. + * </p> + * + * @param method the method invocation of interest + * @return the binding for the given method invocation, or + * <code>null</code> if no binding is available + */ + IMethodBinding resolveMethod(SuperMethodInvocation method) { + return null; + } + + /** + * Resolves the given name and returns the type binding for it. + * <p> + * The implementation of <code>Name.resolveBinding</code> forwards to + * this method. How the name resolves is often a function of the context + * in which the name node is embedded as well as the name itself. + * </p> + * <p> + * The default implementation of this method returns <code>null</code>. + * Subclasses may reimplement. + * </p> + * + * @param name the name of interest + * @return the binding for the name, or <code>null</code> if no binding is + * available + */ + IBinding resolveName(Name name) { + return null; + } + + /** + * Resolves the given package declaration and returns the binding for it. + * <p> + * The implementation of <code>PackageDeclaration.resolveBinding</code> + * forwards to this method. + * </p> + * <p> + * The default implementation of this method returns <code>null</code>. + * Subclasses may reimplement. + * </p> + * + * @param pkg the package declaration of interest + * @return the binding for the given package declaration, or + * <code>null</code> if no binding is available + */ + IPackageBinding resolvePackage(PackageDeclaration pkg) { + return null; + } + + /** + * Resolves the given reference and returns the binding for it. + * <p> + * The implementation of <code>MemberRef.resolveBinding</code> forwards to + * this method. How the name resolves is often a function of the context + * in which the name node is embedded as well as the name itself. + * </p> + * <p> + * The default implementation of this method returns <code>null</code>. + * Subclasses may reimplement. + * </p> + * + * @param ref the reference of interest + * @return the binding for the reference, or <code>null</code> if no binding is + * available + * @since 3.0 + */ + IBinding resolveReference(MemberRef ref) { + return null; + } + + /** + * Resolves the given member value pair and returns the binding for it. + * <p> + * The implementation of <code>MemberValuePair.resolveMemberValuePairBinding</code> forwards to + * this method. How the name resolves is often a function of the context + * in which the name node is embedded as well as the name itself. + * </p> + * <p> + * The default implementation of this method returns <code>null</code>. + * Subclasses may reimplement. + * </p> + * + * @param memberValuePair the member value pair of interest + * @return the binding for the member value pair, or <code>null</code> if no binding is + * available + * @since 3.2 + */ + IMemberValuePairBinding resolveMemberValuePair(MemberValuePair memberValuePair) { + return null; + } + + /** + * Resolves the given reference and returns the binding for it. + * <p> + * The implementation of <code>MethodRef.resolveBinding</code> forwards to + * this method. How the name resolves is often a function of the context + * in which the name node is embedded as well as the name itself. + * </p> + * <p> + * The default implementation of this method returns <code>null</code>. + * Subclasses may reimplement. + * </p> + * + * @param ref the reference of interest + * @return the binding for the reference, or <code>null</code> if no binding is + * available + * @since 3.0 + */ + IBinding resolveReference(MethodRef ref) { + return null; + } + + /** + * Resolves the given annotation type declaration and returns the binding + * for it. + * <p> + * The implementation of <code>AnnotationTypeDeclaration.resolveBinding</code> + * forwards to this method. How the declaration resolves is often a + * function of the context in which the declaration node is embedded as well + * as the declaration subtree itself. + * </p> + * <p> + * The default implementation of this method returns <code>null</code>. + * Subclasses may reimplement. + * </p> + * + * @param type the annotation type declaration of interest + * @return the binding for the given annotation type declaration, or <code>null</code> + * if no binding is available + * @since 3.0 + */ + ITypeBinding resolveType(AnnotationTypeDeclaration type) { + return null; + } + + /** + * Resolves the given anonymous class declaration and returns the binding + * for it. + * <p> + * The implementation of <code>AnonymousClassDeclaration.resolveBinding</code> + * forwards to this method. How the declaration resolves is often a + * function of the context in which the declaration node is embedded as well + * as the declaration subtree itself. + * </p> + * <p> + * The default implementation of this method returns <code>null</code>. + * Subclasses may reimplement. + * </p> + * + * @param type the anonymous class declaration of interest + * @return the binding for the given class declaration, or <code>null</code> + * if no binding is available + */ + ITypeBinding resolveType(AnonymousClassDeclaration type) { + return null; + } + + /** + * Resolves the given enum declaration and returns the binding + * for it. + * <p> + * The implementation of <code>EnumDeclaration.resolveBinding</code> + * forwards to this method. How the enum declaration resolves is often + * a function of the context in which the declaration node is embedded + * as well as the enum declaration subtree itself. + * </p> + * <p> + * The default implementation of this method returns <code>null</code>. + * Subclasses may reimplement. + * </p> + * + * @param type the enum declaration of interest + * @return the binding for the given enum declaration, or <code>null</code> + * if no binding is available + * @since 3.0 + */ + ITypeBinding resolveType(EnumDeclaration type) { + return null; + } + + /** + * Resolves the given type and returns the type binding for it. + * <p> + * The implementation of <code>Type.resolveBinding</code> + * forwards to this method. How the type resolves is often a function + * of the context in which the type node is embedded as well as the type + * subtree itself. + * </p> + * <p> + * The default implementation of this method returns <code>null</code>. + * Subclasses may reimplement. + * </p> + * + * @param type the type of interest + * @return the binding for the given type, or <code>null</code> + * if no binding is available + */ + ITypeBinding resolveType(Type type) { + return null; + } + + /** + * Resolves the given class or interface declaration and returns the binding + * for it. + * <p> + * The implementation of <code>TypeDeclaration.resolveBinding</code> + * (and <code>TypeDeclarationStatement.resolveBinding</code>) forwards + * to this method. How the type declaration resolves is often a function of + * the context in which the type declaration node is embedded as well as the + * type declaration subtree itself. + * </p> + * <p> + * The default implementation of this method returns <code>null</code>. + * Subclasses may reimplement. + * </p> + * + * @param type the class or interface declaration of interest + * @return the binding for the given type declaration, or <code>null</code> + * if no binding is available + */ + ITypeBinding resolveType(TypeDeclaration type) { + return null; + } + + /** + * Resolves the given type parameter and returns the type binding for the + * type parameter. + * <p> + * The implementation of <code>TypeParameter.resolveBinding</code> + * forwards to this method. How the declaration resolves is often a + * function of the context in which the declaration node is embedded as well + * as the declaration subtree itself. + * </p> + * <p> + * The default implementation of this method returns <code>null</code>. + * Subclasses may reimplement. + * </p> + * + * @param typeParameter the type paramter of interest + * @return the binding for the given type parameter, or <code>null</code> + * if no binding is available + * @since 3.1 + */ + ITypeBinding resolveTypeParameter(TypeParameter typeParameter) { + return null; + } + + /** + * Resolves the given enum constant declaration and returns the binding for + * the field. + * <p> + * The implementation of <code>EnumConstantDeclaration.resolveVariable</code> + * forwards to this method. + * </p> + * <p> + * The default implementation of this method returns <code>null</code>. + * Subclasses may reimplement. + * </p> + * + * @param enumConstant the enum constant declaration of interest + * @return the field binding for the given enum constant declaration, or + * <code>null</code> if no binding is available + * @since 3.0 + */ + IVariableBinding resolveVariable(EnumConstantDeclaration enumConstant) { + return null; + } + + /** + * Resolves the given variable declaration and returns the binding for it. + * <p> + * The implementation of <code>VariableDeclaration.resolveBinding</code> + * forwards to this method. How the variable declaration resolves is often + * a function of the context in which the variable declaration node is + * embedded as well as the variable declaration subtree itself. VariableDeclaration + * declarations used as local variable, formal parameter and exception + * variables resolve to local variable bindings; variable declarations + * used to declare fields resolve to field bindings. + * </p> + * <p> + * The default implementation of this method returns <code>null</code>. + * Subclasses may reimplement. + * </p> + * + * @param variable the variable declaration of interest + * @return the binding for the given variable declaration, or + * <code>null</code> if no binding is available + */ + IVariableBinding resolveVariable(VariableDeclaration variable) { + return null; + } + + /** + * Resolves the given well known type by name and returns the type binding + * for it. + * <p> + * The implementation of <code>AST.resolveWellKnownType</code> + * forwards to this method. + * </p> + * <p> + * The default implementation of this method returns <code>null</code>. + * Subclasses may reimplement. + * </p> + * + * @param name the name of a well known type + * @return the corresponding type binding, or <code>null<code> if the + * named type is not considered well known or if no binding can be found + * for it + */ + ITypeBinding resolveWellKnownType(String name) { + return null; + } + + /** + * Resolves the given annotation instance and returns the DOM representation for it. + * <p> + * The implementation of {@link Annotation#resolveAnnotationBinding()} + * forwards to this method. + * </p> + * <p> + * The default implementation of this method returns <code>null</code>. + * Subclasses may reimplement. + * </p> + * + * @param annotation the annotation ast node of interest + * @return the DOM annotation representation for the given ast node, or + * <code>null</code> if none is available + */ + IAnnotationBinding resolveAnnotation(Annotation annotation) { + return null; + } + + /** + * Answer an array type binding with the given type binding and the given + * dimensions. + * + * <p>If the given type binding is an array binding, then the resulting dimensions is the given dimensions + * plus the existing dimensions of the array binding. Otherwise the resulting dimensions is the given + * dimensions.</p> + * + * <p> + * The default implementation of this method returns <code>null</code>. + * Subclasses may reimplement. + * </p> + * + * @param typeBinding the given type binding + * @param dimensions the given dimensions + * @return an array type binding with the given type binding and the given + * dimensions + * @throws IllegalArgumentException if the type binding represents the <code>void</code> type binding + */ + ITypeBinding resolveArrayType(ITypeBinding typeBinding, int dimensions) { + return null; + } + + /** + * Returns the compilation unit scope used by this binding resolver. + * Returns <code>null</code> if none. + * + * @return the compilation unit scope by this resolver, or <code>null</code> if none. + */ + public CompilationUnitScope scope() { + return null; + } + + /** + * Allows the user to store information about the given old/new pair of + * AST nodes. + * <p> + * The default implementation of this method does nothing. + * Subclasses may reimplement. + * </p> + * + * @param newNode the new AST node + * @param oldASTNode the old AST node + */ + void store(ASTNode newNode, org.eclipse.jdt.internal.compiler.ast.ASTNode oldASTNode) { + // default implementation: do nothing + } + + /** + * Allows the user to update information about the given old/new pair of + * AST nodes. + * <p> + * The default implementation of this method does nothing. + * Subclasses may reimplement. + * </p> + * + * @param node the old AST node + * @param newNode the new AST node + */ + void updateKey(ASTNode node, ASTNode newNode) { + // default implementation: do nothing + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Block.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Block.java new file mode 100644 index 000000000..23c429af4 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Block.java @@ -0,0 +1,169 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Block statement AST node type. + * + * <pre> + * Block: + * <b>{</b> { Statement } <b>}</b> + * </pre> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class Block extends Statement { + + /** + * The "statements" structural property of this node type. + * @since 3.0 + */ + public static final ChildListPropertyDescriptor STATEMENTS_PROPERTY = + new ChildListPropertyDescriptor(Block.class, "statements", Statement.class, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List properyList = new ArrayList(2); + createPropertyList(Block.class, properyList); + addProperty(STATEMENTS_PROPERTY, properyList); + PROPERTY_DESCRIPTORS = reapPropertyList(properyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The list of statements (element type: <code>Statement</code>). + * Defaults to an empty list. + */ + private ASTNode.NodeList statements = + new ASTNode.NodeList(STATEMENTS_PROPERTY); + + /** + * Creates a new unparented block node owned by the given AST. + * By default, the block is empty. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + Block(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalGetChildListProperty(ChildListPropertyDescriptor property) { + if (property == STATEMENTS_PROPERTY) { + return statements(); + } + // allow default implementation to flag the error + return super.internalGetChildListProperty(property); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return BLOCK; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + Block result = new Block(target); + result.setSourceRange(getStartPosition(), getLength()); + result.copyLeadingComment(this); + result.statements().addAll( + ASTNode.copySubtrees(target, statements())); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + acceptChildren(visitor, this.statements); + } + visitor.endVisit(this); + } + + /** + * Returns the live list of statements in this block. Adding and + * removing nodes from this list affects this node dynamically. + * All nodes in this list must be <code>Statement</code>s; + * attempts to add any other type of node will trigger an + * exception. + * + * @return the live list of statements in this block + * (element type: <code>Statement</code>) + */ + public List statements() { + return this.statements; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return super.memSize() + 1 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return memSize() + this.statements.listSize(); + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/BlockComment.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/BlockComment.java new file mode 100644 index 000000000..88d89866d --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/BlockComment.java @@ -0,0 +1,130 @@ +/******************************************************************************* + * Copyright (c) 2004, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Block comment AST node type. + * <p> + * Block comments (also called "traditional" comments in JLS 3.7) + * begin with "/*", may contain line breaks, and must end + * with "*/". Following the definition in the JLS (first edition + * but not second edition), block comment normally exclude comments + * that begin with "/*#42;", which are instead classified as doc + * comments ({@link Javadoc}). + * </p> + * <p> + * Note that this node type is a comment placeholder, and is + * only useful for recording the source range where a comment + * was found in a source string. It is not useful for creating + * comments. + * </p> + * + * @since 3.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public final class BlockComment extends Comment { + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List properyList = new ArrayList(1); + createPropertyList(BlockComment.class, properyList); + PROPERTY_DESCRIPTORS = reapPropertyList(properyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * Creates a new block comment node owned by the given AST. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + BlockComment(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return BLOCK_COMMENT; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + BlockComment result = new BlockComment(target); + result.setSourceRange(getStartPosition(), getLength()); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + visitor.visit(this); + visitor.endVisit(this); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return super.memSize(); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return memSize(); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/BodyDeclaration.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/BodyDeclaration.java new file mode 100644 index 000000000..6ac9d9c22 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/BodyDeclaration.java @@ -0,0 +1,282 @@ +/******************************************************************************* + * Copyright (c) 2000, 2009 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.Iterator; +import java.util.List; + +/** + * Abstract base class of all AST nodes that represent body declarations + * that may appear in the body of some kind of class or interface declaration, + * including anonymous class declarations, enumeration declarations, and + * enumeration constant declarations. + * <p> + * For JLS2: + * <pre> + * BodyDeclaration: + * ClassDeclaration + * InterfaceDeclaration + * MethodDeclaration + * ConstructorDeclaration + * FieldDeclaration + * Initializer + * </pre> + * For JLS3, a number of new node types were introduced: + * <pre> + * BodyDeclaration: + * ClassDeclaration + * InterfaceDeclaration + * EnumDeclaration + * MethodDeclaration + * ConstructorDeclaration + * FieldDeclaration + * Initializer + * EnumConstantDeclaration + * AnnotationTypeDeclaration + * AnnotationTypeMemberDeclaration + * </pre> + * </p> + * <p> + * All types of body declarations carry modifiers (and annotations), although they differ in + * which modifiers are allowed. Most types of body declarations can carry a + * doc comment; Initializer is the only ones that does not. The source range + * for body declarations always includes the doc comment if present. + * </p> + * + * @since 2.0 + */ +public abstract class BodyDeclaration extends ASTNode { + + /** + * The doc comment, or <code>null</code> if none. + * Defaults to none. + */ + Javadoc optionalDocComment = null; + + /** + * The modifier flags; bit-wise or of Modifier flags. + * Defaults to none. Not used in 3.0. + * @since 3.0 - field was moved up from subclasses + */ + private int modifierFlags = Modifier.NONE; + + /** + * The extended modifiers (element type: <code>IExtendedModifier</code>). + * Null in JLS2. Added in JLS3; defaults to an empty list + * (see constructor). + * + * @since 3.0 + */ + ASTNode.NodeList modifiers = null; + + /** + * Returns structural property descriptor for the "modifiers" property + * of this node as used in JLS2. + * + * @return the property descriptor + */ + abstract SimplePropertyDescriptor internalModifiersProperty(); + + /** + * Returns structural property descriptor for the "modifiers" property + * of this node as used in JLS3. + * + * @return the property descriptor + */ + abstract ChildListPropertyDescriptor internalModifiers2Property(); + + /** + * Returns structural property descriptor for the "modifiers" property + * of this node as used in JLS3. + * + * @return the property descriptor + * @since 3.1 + */ + public final ChildListPropertyDescriptor getModifiersProperty() { + // important: return property for AST.JLS3 + return internalModifiers2Property(); + } + + /** + * Returns structural property descriptor for the "javadoc" property + * of this node. + * + * @return the property descriptor + */ + abstract ChildPropertyDescriptor internalJavadocProperty(); + + /** + * Returns structural property descriptor for the "javadoc" property + * of this node. + * + * @return the property descriptor + * @since 3.1 + */ + public final ChildPropertyDescriptor getJavadocProperty() { + return internalJavadocProperty(); + } + + /** + * Creates and returns a structural property descriptor for the + * "javadoc" property declared on the given concrete node type. + * + * @return the property descriptor + */ + static final ChildPropertyDescriptor internalJavadocPropertyFactory(Class nodeClass) { + return new ChildPropertyDescriptor(nodeClass, "javadoc", Javadoc.class, OPTIONAL, NO_CYCLE_RISK); //$NON-NLS-1$ + } + + /** + * Creates and returns a structural property descriptor for the + * "modifiers" property declared on the given concrete node type. + * + * @return the property descriptor + */ + static final SimplePropertyDescriptor internalModifiersPropertyFactory(Class nodeClass) { + return new SimplePropertyDescriptor(nodeClass, "modifiers", int.class, MANDATORY); //$NON-NLS-1$ + } + + /** + * Creates and returns a structural property descriptor for the + * "modifiers" property declared on the given concrete node type. + * + * @return the property descriptor + */ + static final ChildListPropertyDescriptor internalModifiers2PropertyFactory(Class nodeClass) { + return new ChildListPropertyDescriptor(nodeClass, "modifiers", IExtendedModifier.class, CYCLE_RISK); //$NON-NLS-1$ + } + + /** + * Creates a new AST node for a body declaration node owned by the + * given AST. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + BodyDeclaration(AST ast) { + super(ast); + if (ast.apiLevel >= AST.JLS3) { + this.modifiers = new ASTNode.NodeList(internalModifiers2Property()); + } + } + + /** + * Returns the doc comment node. + * + * @return the doc comment node, or <code>null</code> if none + */ + public Javadoc getJavadoc() { + return this.optionalDocComment; + } + + /** + * Sets or clears the doc comment node. + * + * @param docComment the doc comment node, or <code>null</code> if none + * @exception IllegalArgumentException if the doc comment string is invalid + */ + public void setJavadoc(Javadoc docComment) { + ChildPropertyDescriptor p = internalJavadocProperty(); + ASTNode oldChild = this.optionalDocComment; + preReplaceChild(oldChild, docComment, p); + this.optionalDocComment = docComment; + postReplaceChild(oldChild, docComment, p); + } + + /** + * Returns the modifiers explicitly specified on this declaration. + * <p> + * In the JLS3 API, this method is a convenience method that + * computes these flags from <code>modifiers()</code>. + * </p> + * + * @return the bit-wise or of <code>Modifier</code> constants + * @see Modifier + */ + public int getModifiers() { + // more efficient than checking getAST().API_LEVEL + if (this.modifiers == null) { + // JLS2 behavior - bona fide property + return this.modifierFlags; + } else { + // JLS3 behavior - convenience method + // performance could be improved by caching computed flags + // but this would require tracking changes to this.modifiers + int computedmodifierFlags = Modifier.NONE; + for (Iterator it = modifiers().iterator(); it.hasNext(); ) { + Object x = it.next(); + if (x instanceof Modifier) { + computedmodifierFlags |= ((Modifier) x).getKeyword().toFlagValue(); + } + } + return computedmodifierFlags; + } + } + + /** + * Sets the modifiers explicitly specified on this declaration (JLS2 API only). + * + * @param modifiers the given modifiers (bit-wise or of <code>Modifier</code> constants) + * @exception UnsupportedOperationException if this operation is used in + * an AST later than JLS2 + * @see Modifier + * @deprecated In the JLS3 API, this method is replaced by + * {@link #modifiers()} which contains a list of a <code>Modifier</code> nodes. + */ + public void setModifiers(int modifiers) { + internalSetModifiers(modifiers); + } + + /** + * Internal synonym for deprecated method. Used to avoid + * deprecation warnings. + * @since 3.1 + */ + /*package*/ final void internalSetModifiers(int pmodifiers) { + // more efficient than just calling supportedOnlyIn2() to check + if (this.modifiers != null) { + supportedOnlyIn2(); + } + SimplePropertyDescriptor p = internalModifiersProperty(); + preValueChange(p); + this.modifierFlags = pmodifiers; + postValueChange(p); + } + + /** + * Returns the live ordered list of modifiers and annotations + * of this declaration (added in JLS3 API). + * + * @return the live list of modifiers and annotations + * (element type: <code>IExtendedModifier</code>) + * @exception UnsupportedOperationException if this operation is used in + * a JLS2 AST + * @since 3.1 + */ + public List modifiers() { + // more efficient than just calling unsupportedIn2() to check + if (this.modifiers == null) { + unsupportedIn2(); + } + return this.modifiers; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return BASE_NODE_SIZE + 3 * 4; + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/BooleanLiteral.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/BooleanLiteral.java new file mode 100644 index 000000000..f9da563a9 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/BooleanLiteral.java @@ -0,0 +1,178 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Boolean literal node. + * + * <pre> + * BooleanLiteral: + * <b>true</b> + * <b>false</b> + * </pre> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class BooleanLiteral extends Expression { + + /** + * The "booleanValue" structural property of this node type. + * @since 3.0 + */ + public static final SimplePropertyDescriptor BOOLEAN_VALUE_PROPERTY = + new SimplePropertyDescriptor(BooleanLiteral.class, "booleanValue", boolean.class, MANDATORY); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List properyList = new ArrayList(2); + createPropertyList(BooleanLiteral.class, properyList); + addProperty(BOOLEAN_VALUE_PROPERTY, properyList); + PROPERTY_DESCRIPTORS = reapPropertyList(properyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The boolean; defaults to the literal for <code>false</code>. + */ + private boolean value = false; + + /** + * Creates a new unparented boolean literal node owned by the given AST. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + BooleanLiteral(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean internalGetSetBooleanProperty(SimplePropertyDescriptor property, boolean get, boolean newValue) { + if (property == BOOLEAN_VALUE_PROPERTY) { + if (get) { + return booleanValue(); + } else { + setBooleanValue(newValue); + return false; + } + } + // allow default implementation to flag the error + return super.internalGetSetBooleanProperty(property, get, newValue); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return BOOLEAN_LITERAL; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + BooleanLiteral result = new BooleanLiteral(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setBooleanValue(booleanValue()); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + visitor.visit(this); + visitor.endVisit(this); + } + + /** + * Returns the boolean value of this boolean literal node. + * + * @return <code>true</code> for the boolean literal spelled + * <code>"true"</code>, and <code>false</code> for the boolean literal + * spelled <code>"false"</code>. + */ + public boolean booleanValue() { + return this.value; + } + + /** + * Sets the boolean value of this boolean literal node. + * + * @param value <code>true</code> for the boolean literal spelled + * <code>"true"</code>, and <code>false</code> for the boolean literal + * spelled <code>"false"</code>. + */ + public void setBooleanValue(boolean value) { + preValueChange(BOOLEAN_VALUE_PROPERTY); + this.value = value; + postValueChange(BOOLEAN_VALUE_PROPERTY); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return BASE_NODE_SIZE + 1 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return memSize(); + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/BreakStatement.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/BreakStatement.java new file mode 100644 index 000000000..0086aa565 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/BreakStatement.java @@ -0,0 +1,188 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Break statement AST node type. + * + * <pre> + * BreakStatement: + * <b>break</b> [ Identifier ] <b>;</b> + * </pre> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class BreakStatement extends Statement { + + /** + * The "label" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor LABEL_PROPERTY = + new ChildPropertyDescriptor(BreakStatement.class, "label", SimpleName.class, OPTIONAL, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List properyList = new ArrayList(2); + createPropertyList(BreakStatement.class, properyList); + addProperty(LABEL_PROPERTY, properyList); + PROPERTY_DESCRIPTORS = reapPropertyList(properyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The label, or <code>null</code> if none; none by default. + */ + private SimpleName optionalLabel = null; + + /** + * Creates a new unparented break statement node owned by the given + * AST. By default, the break statement has no label. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + BreakStatement(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == LABEL_PROPERTY) { + if (get) { + return getLabel(); + } else { + setLabel((SimpleName) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return BREAK_STATEMENT; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + BreakStatement result = new BreakStatement(target); + result.setSourceRange(getStartPosition(), getLength()); + result.copyLeadingComment(this); + result.setLabel((SimpleName) ASTNode.copySubtree(target, getLabel())); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + acceptChild(visitor, getLabel()); + } + visitor.endVisit(this); + } + + /** + * Returns the label of this break statement, or <code>null</code> if + * there is none. + * + * @return the label, or <code>null</code> if there is none + */ + public SimpleName getLabel() { + return this.optionalLabel; + } + + /** + * Sets or clears the label of this break statement. + * + * @param label the label, or <code>null</code> if + * there is none + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public void setLabel(SimpleName label) { + ASTNode oldChild = this.optionalLabel; + preReplaceChild(oldChild, label, LABEL_PROPERTY); + this.optionalLabel = label; + postReplaceChild(oldChild, label, LABEL_PROPERTY); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return super.memSize() + 1 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.optionalLabel == null ? 0 : getLabel().treeSize()); + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CallinMappingDeclaration.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CallinMappingDeclaration.java new file mode 100644 index 000000000..d291e278c --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CallinMappingDeclaration.java @@ -0,0 +1,523 @@ +/********************************************************************** + * This file is part of "Object Teams Development Tooling"-Software + * + * Copyright 2004, 2006 Fraunhofer Gesellschaft, Munich, Germany, + * for its Fraunhofer Institute for Computer Architecture and Software + * Technology (FIRST), Berlin, Germany and Technical University Berlin, + * Germany. + * + * 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 + * $Id: CallinMappingDeclaration.java 23416 2010-02-03 19:59:31Z stephan $ + * + * Please visit http://www.eclipse.org/objectteams for updates and contact. + * + * Contributors: + * Fraunhofer FIRST - Initial API and implementation + * Technical University Berlin - Initial API and implementation + **********************************************************************/ +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + + +/** + * NEW for OTDT + * + * Represents a callin binding of a role method with one ore more base methods (OTJLD §4). + * Callin bindings must have one modifier (before, replace, after) + * and may have parameter mappings. A replace callin may also have a result mapping. + * e.g.: + * + * ranges from: + * <code>roleMethod <- after baseMethod;</code> + * to: + * <pre> + * void roleMethod(MyObject obj) <- + * after char[] baseMethod(String name, SomeClass cls) with + * { + * obj <- cls.foo(), + * } + * </pre> + * or: + * <pre> + * char[] roleMethod(MyObject obj) <- + * replace char[] baseMethod(MyObject o, String name) with + * { + * obj <- o, + * result <- result + * } + * </pre> + * + * Callin bindings consist of + * <ol> + * <li> a name as mentioned in source code or a generated name "<File:Line,Col>". + * <li> role_method_designator "<-" callin_modifier base_method_designator; + * <ol> + * <li> method designators may or may not contain parameters lists and return type + * but no modifiers (see §3.1(c)). + * <li> callin_modifiers are replace, before, after. + * </ol> + * <li> Parameter mappings + * <ol> + * <li> result mapping (only replace) + * </ol> + * </ol> + * + * Callin bindinds can be used in the following AST-nodes: + * TypeDeclaration (compiler ast) + * RoleTypeDeclaration (dom/ast) + * + * @author mkr + */ +public class CallinMappingDeclaration extends AbstractMethodMappingDeclaration +{ + public static final String CALLIN = "<-"; //$NON-NLS-1$ + + /** + * Creates a new AST node for a callin mapping declaration owned + * by the given AST. By default, the declaration is for a callin mapping + * of an unspecified, but legal, name; + * <p> + * N.B. This constructor is package-private; all subclasses must be + * declared in the same package; clients are unable to declare + * additional subclasses. + * </p> + * + * @param ast the AST that is to own this node + */ + CallinMappingDeclaration(AST ast) + { + super(ast); + } + + /** + * The "names" structural property of this node type. + */ + public static final ChildPropertyDescriptor NAME_PROPERTY = + new ChildPropertyDescriptor(CallinMappingDeclaration.class, "name", SimpleName.class, OPTIONAL, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "modifiers" structural property of this node type (added in JLS3 API). + * @since 3.1 + */ + public static final ChildListPropertyDescriptor MODIFIERS2_PROPERTY = + internalModifiers2PropertyFactory(CallinMappingDeclaration.class); + + + /** + * The "javadoc" structural property of this node type. + */ + public static final ChildPropertyDescriptor JAVADOC_PROPERTY = + internalJavadocPropertyFactory(CallinMappingDeclaration.class); + + /** + * The "roleMappingElement" structural property of this node type. + */ + public static final ChildPropertyDescriptor ROLE_MAPPING_ELEMENT_PROPERTY = + new ChildPropertyDescriptor(CallinMappingDeclaration.class, "roleMappingElement", MethodMappingElement.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The binding operator structural property ("<- modifier") + * @since 1.3.1 + */ + public static final ChildPropertyDescriptor BINDING_OPERATOR_PROPERTY = + new ChildPropertyDescriptor(CallinMappingDeclaration.class, "bindingOperator", MethodBindingOperator.class, MANDATORY, NO_CYCLE_RISK); + + /** + * The "baseMappingElements" structural property of this node type. + */ + public static final ChildListPropertyDescriptor BASE_MAPPING_ELEMENTS_PROPERTY = + new ChildListPropertyDescriptor(CallinMappingDeclaration.class, "baseMappingElements", MethodMappingElement.class, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "guardPredicate" structural property of this node type. + * @since 0.9.25 + */ + public static final ChildPropertyDescriptor GUARD_PROPERTY = + new ChildPropertyDescriptor(CallinMappingDeclaration.class, "guardPredicate", GuardPredicateDeclaration.class, OPTIONAL, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "parameter mappings" structural property of this node type. + */ + public static final ChildListPropertyDescriptor PARAMETER_MAPPINGS_PROPERTY = + internalParameterMappingPropertyFactory(CallinMappingDeclaration.class); + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS_2_0; + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + + private static final List PROPERTY_DESCRIPTORS_3_0; + + private SimpleName _labelName = null; + + private MethodMappingElement _roleMappingElement = null; // FIXME(SH): should be MethodSpec?? + ASTNode.NodeList _baseMappingElements = new ASTNode.NodeList(BASE_MAPPING_ELEMENTS_PROPERTY); + + GuardPredicateDeclaration _optionalGuardPredicate = null; + + static + { + List propertyList = new ArrayList(7); + createPropertyList(CallinMappingDeclaration.class, propertyList); + addProperty(NAME_PROPERTY, propertyList); + addProperty(JAVADOC_PROPERTY, propertyList); + addProperty(ROLE_MAPPING_ELEMENT_PROPERTY, propertyList); + addProperty(BINDING_OPERATOR_PROPERTY, propertyList); + addProperty(BASE_MAPPING_ELEMENTS_PROPERTY, propertyList); + addProperty(PARAMETER_MAPPINGS_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS_2_0 = reapPropertyList(propertyList); + + propertyList = new ArrayList(9); + createPropertyList(CallinMappingDeclaration.class, propertyList); + addProperty(NAME_PROPERTY, propertyList); + addProperty(MODIFIERS2_PROPERTY, propertyList); // for annotations + addProperty(JAVADOC_PROPERTY, propertyList); + addProperty(ROLE_MAPPING_ELEMENT_PROPERTY, propertyList); + addProperty(BINDING_OPERATOR_PROPERTY, propertyList); + addProperty(BASE_MAPPING_ELEMENTS_PROPERTY, propertyList); + addProperty(GUARD_PROPERTY, propertyList); + addProperty(PARAMETER_MAPPINGS_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS_3_0 = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the AST.JLS* constants + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + */ + public static List propertyDescriptors(int apiLevel) + { + if(apiLevel == AST.JLS3) + return PROPERTY_DESCRIPTORS_3_0; + else + return PROPERTY_DESCRIPTORS_2_0; + } + + final SimplePropertyDescriptor internalModifiersProperty() + { + throw new UnsupportedOperationException("JLS2 not supported"); //$NON-NLS-1$ + } + + final ChildListPropertyDescriptor internalModifiers2Property() + { + return MODIFIERS2_PROPERTY; + } + + ChildPropertyDescriptor internalGetRoleElementProperty() { + return ROLE_MAPPING_ELEMENT_PROPERTY; + } + + protected ChildPropertyDescriptor internalGetBindingOperatorProperty() { + return BINDING_OPERATOR_PROPERTY; + } + + final ChildListPropertyDescriptor internalParameterMappingsProperty() + { + return PARAMETER_MAPPINGS_PROPERTY; + } + + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) + { + if (property == JAVADOC_PROPERTY) + { + if (get) { + return getJavadoc(); + } else { + setJavadoc((Javadoc) child); + return null; + } + } + if (property == NAME_PROPERTY) { + if (get) { + return getName(); + } else { + setName((SimpleName)child); + return null; + } + } + // name is not a child (SimpleName) but a direct String property + // callin modifier is not a child either but a direct int property + if (property == ROLE_MAPPING_ELEMENT_PROPERTY) + { + if (get) { + return getRoleMappingElement(); + } else { + setRoleMappingElement((MethodSpec) child); + return null; + } + } + if (property == GUARD_PROPERTY) + { + if (get) { + return getGuardPredicate(); + } else { + setGuardPredicate((GuardPredicateDeclaration) child); + return null; + } + } + + // allow default implementation to flag the error (incl. handling of elements common to all method mappings): + return super.internalGetSetChildProperty(property, get, child); + } + + final List internalGetChildListProperty(ChildListPropertyDescriptor property) + { + if(property == MODIFIERS2_PROPERTY) + return modifiers(); + + if (property == BASE_MAPPING_ELEMENTS_PROPERTY) + return getBaseMappingElements(); + + if (property == PARAMETER_MAPPINGS_PROPERTY) + return getParameterMappings(); + + // allow default implementation to flag the error + return super.internalGetChildListProperty(property); + } + + ChildPropertyDescriptor internalJavadocProperty() + { + return JAVADOC_PROPERTY; + } + + List internalStructuralPropertiesForType(int apiLevel) + { + return propertyDescriptors(apiLevel); + } + + int getNodeType0() + { + return CALLIN_MAPPING_DECLARATION; + } + + @SuppressWarnings("unchecked") + ASTNode clone0(AST target) + { + CallinMappingDeclaration result = new CallinMappingDeclaration(target); + result.setName(this.getName()); + if (this.ast.apiLevel >= AST.JLS3) + result.modifiers().addAll(ASTNode.copySubtrees(target, modifiers())); // annotations + result.setSourceRange(this.getStartPosition(), this.getLength()); + result.setJavadoc( + (Javadoc) ASTNode.copySubtree(target, getJavadoc())); + result.setRoleMappingElement( + (MethodSpec) ASTNode.copySubtree(target, getRoleMappingElement())); + result.setBindingOperator((MethodBindingOperator)bindingOperator().clone(target)); + result.getBaseMappingElements().addAll( + ASTNode.copySubtrees(target, getBaseMappingElements())); + result.setGuardPredicate((GuardPredicateDeclaration)ASTNode.copySubtree(target, getGuardPredicate())); + result.getParameterMappings().addAll( + ASTNode.copySubtrees(target, getParameterMappings())); + return result; + } + + + + boolean subtreeMatch0(ASTMatcher matcher, Object other) + { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + void accept0(ASTVisitor visitor) + { + boolean visitChildren = visitor.visit(this); + if (visitChildren) + { + // visit children in normal left to right reading order + acceptChild(visitor, getJavadoc()); + acceptChild(visitor, _labelName); + acceptChild(visitor, _roleMappingElement); + if (this.ast.apiLevel >= AST.JLS3) + acceptChildren(visitor, modifiers); + acceptChild(visitor, bindingOperator); + acceptChildren(visitor, _baseMappingElements); + acceptChild(visitor, this.getGuardPredicate()); + acceptChildren(visitor, _parameterMappings); + } + visitor.endVisit(this); + } + + void appendDebugString(StringBuffer buffer) { + if (getName() != null) { + buffer.append(getName().getIdentifier()); + buffer.append(':'); + } + super.appendDebugString(buffer); + } + + int treeSize() + { + return memSize() + (super.optionalDocComment == null + ? 0 + : getJavadoc().treeSize()); + } + + /** + * Returns the method spec left of the callin arrow. + * @return the left method spec, i.e. the declaring role method + */ + @Override + public MethodMappingElement getRoleMappingElement() + { + if (_roleMappingElement == null) + { + // lazy init must be thread-safe for readers + synchronized (this) + { + if (_roleMappingElement == null) + { + preLazyInit(); + _roleMappingElement = new MethodSpec(this.ast); + postLazyInit(_roleMappingElement, ROLE_MAPPING_ELEMENT_PROPERTY); + } + } + } + return _roleMappingElement; + } + + /** + * Sets the left method spec (role method spec) declared in this callin + * mapping declaration to the given method spec. + * + * @param roleMappingElement + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public void setRoleMappingElement(MethodMappingElement roleMappingElement) + { + if (roleMappingElement == null) + { + throw new IllegalArgumentException(); + } + ASTNode oldChild = _roleMappingElement; + preReplaceChild(oldChild, roleMappingElement, ROLE_MAPPING_ELEMENT_PROPERTY); + _roleMappingElement = roleMappingElement; + postReplaceChild(oldChild, roleMappingElement, ROLE_MAPPING_ELEMENT_PROPERTY); + } + + /** + * Returns the live ordered list of base method specs for this + * callin mapping declaration. + * + * @return the live list of base method specs + * (element type: <code>IExtendedModifier</code>) + * @exception UnsupportedOperationException if this operation is used in + * a JLS2 AST + */ + public List getBaseMappingElements() + { + return _baseMappingElements; + } + + /** + * Returns the callin modifiers explicitly specified on this declaration. + * + * @return exactly one of before, after, replace using constants from Modifier + * @see Modifier + */ + public int getCallinModifier() + { + return bindingOperator.getBindingModifier(); + } + + /** + * Sets the callin modifier explicitly specified on this declaration. + * + * @param modifiers the given modifiers (bit-wise or of <code>Modifier</code> constants) + * @see Modifier + * @deprecated use setBindingOperator instead + */ + public void setCallinModifier(int modifiers) + { + setCallinModifier(this.ast.newModifier(Modifier.ModifierKeyword.fromFlagValue(modifiers))); + } + + /** + * @deprecated use setBindingOperator + */ + public void setCallinModifier(Modifier modifier) { + if (this.bindingOperator == null) { + MethodBindingOperator op = new MethodBindingOperator(this.ast); + op.setBindingKind(MethodBindingOperator.KIND_CALLIN); + op.setBindingModifier(modifier); + this.setBindingOperator(op); + } else { + this.bindingOperator.setBindingModifier(modifier); + } + } + + /** + * Returns the callin modifier for this callin mapping declaration. + * + * @see Modifier + * @return one of before, after, replace + */ + public Modifier callinModifier() + { + return this.bindingOperator.bindingModifier(); + } + + public boolean hasName() { + return _labelName != null && _labelName.getIdentifier().charAt(0) != '<'; + } + public void setName(SimpleName name) + { + if (name == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this._labelName; + preReplaceChild(oldChild, name, NAME_PROPERTY); + this._labelName = name; + postReplaceChild(oldChild, name, NAME_PROPERTY); + + } + + public SimpleName getName() { + return this._labelName; + } + + public void setGuardPredicate(GuardPredicateDeclaration predicate) { + ASTNode oldChild = this._optionalGuardPredicate; + preReplaceChild(oldChild, predicate, GUARD_PROPERTY); + this._optionalGuardPredicate = predicate; + postReplaceChild(oldChild, predicate, GUARD_PROPERTY); + } + + public GuardPredicateDeclaration getGuardPredicate() { + return _optionalGuardPredicate; + } + + /** + * Return whether a static base method is bound such that + * no instance will be passed through this binding + * (one static base method suffices to determine staticness). + */ + public boolean isStatic() { + for (Object baseElem : this.getBaseMappingElements()) { + IMethodBinding baseMethod = ((MethodSpec)baseElem).resolveBinding(); + if (baseMethod != null && Modifier.isStatic(baseMethod.getModifiers())) + return true; + } + return false; + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CalloutMappingDeclaration.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CalloutMappingDeclaration.java new file mode 100644 index 000000000..9bf8f86bf --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CalloutMappingDeclaration.java @@ -0,0 +1,427 @@ +/********************************************************************** + * This file is part of "Object Teams Development Tooling"-Software + * + * Copyright 2004, 2006 Fraunhofer Gesellschaft, Munich, Germany, + * for its Fraunhofer Institute for Computer Architecture and Software + * Technology (FIRST), Berlin, Germany and Technical University Berlin, + * Germany. + * + * 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 + * $Id: CalloutMappingDeclaration.java 23416 2010-02-03 19:59:31Z stephan $ + * + * Please visit http://www.eclipse.org/objectteams for updates and contact. + * + * Contributors: + * Fraunhofer FIRST - Initial API and implementation + * Technical University Berlin - Initial API and implementation + **********************************************************************/ +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * NEW for OTDT + * + * Represents DOM-ASTNode for Callout Bindings (OTJLD §2.4.2), + * which has to handle code from e.g. : + * foo => bar; + * to e.g. : + * Integer absoluteValue(Integer integer) -> int abs(int i) with { + * integer.intValue() -> i, + * result <- new Integer(result) + * } + * and also the callout to field binding: + * - without value mapping: + * + * setValue -> set value; + * + * int getValue() -> get int value; + * + * - with value mappings: + * + * Integer getValue() -> get int val + * with { result <- new Integer(result) } + * + * void setValue(Integer i) -> set int val + * with { integer.intValue() -> val } + * + * + * This class consists of one MethodSpec for bound role method and one MethodSpec for base method + * or FieldAccessSpec for access to a field of the base class. Also it consists of + * a callout kind and an optionally mapping of parameters. + * + * This node is used in TypeDeclaration, particulary in RoleTypeDeclaration. + * + * @author ike + */ +public class CalloutMappingDeclaration extends AbstractMethodMappingDeclaration +{ + public static final String CALLOUT = "->"; //$NON-NLS-1$ + public static final String CALLOUT_OVERRIDE = "=>"; //$NON-NLS-1$ + + /** + * Creates a new AST node for a callout mapping declaration owned + * by the given AST. By default, the declaration is for a callout mapping + * of an unspecified, but legal, name; + * <p> + * N.B. This constructor is package-private; all subclasses must be + * declared in the same package; clients are unable to declare + * additional subclasses. + * </p> + * + * @param ast the AST that is to own this node + */ + CalloutMappingDeclaration(AST ast) + { + super(ast); + } + + /** + * The "javadoc" structural property of this node type. + */ + public static final ChildPropertyDescriptor JAVADOC_PROPERTY = + internalJavadocPropertyFactory(CalloutMappingDeclaration.class); + + /** + * The left "methodSpec" structural property of this node type. + */ + public static final ChildPropertyDescriptor ROLE_MAPPING_ELEMENT_PROPERTY = + new ChildPropertyDescriptor(CalloutMappingDeclaration.class, "roleMappingElement", MethodMappingElement.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + /** + * The binding operator structural property ("<- modifier") + * @since 1.3.1 + */ + public static final ChildPropertyDescriptor BINDING_OPERATOR_PROPERTY = + new ChildPropertyDescriptor(CalloutMappingDeclaration.class, "bindingOperator", MethodBindingOperator.class, MANDATORY, NO_CYCLE_RISK); + + /** + * The right "methodSpec" structural property of this node type. + */ + public static final ChildPropertyDescriptor BASE_MAPPING_ELEMENT_PROPERTY = + new ChildPropertyDescriptor(CalloutMappingDeclaration.class, "baseMappingElement", MethodMappingElement.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "signature" structural property of this node type. + */ + public static final SimplePropertyDescriptor SIGNATURE_PROPERTY = + new SimplePropertyDescriptor(CalloutMappingDeclaration.class, "signature", boolean.class, MANDATORY); //$NON-NLS-1$ + + /** + * The "parameterMappings" structural property of this node type. + */ + public static final ChildListPropertyDescriptor PARAMETER_MAPPINGS_PROPERTY = + internalParameterMappingPropertyFactory(CalloutMappingDeclaration.class); + + /** + * The "modifiers" structural property of this node type. + */ + public static final SimplePropertyDescriptor MODIFIERS_PROPERTY = + internalModifiersPropertyFactory(CalloutMappingDeclaration.class); + + /** + * The "modifiers2" structural property of this node type. + */ + public static final ChildListPropertyDescriptor MODIFIERS2_PROPERTY = + internalModifiers2PropertyFactory(CalloutMappingDeclaration.class); + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS_2_0; + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + + private static final List PROPERTY_DESCRIPTORS_3_0; + + private MethodMappingElement _baseMappingElement = null; + private boolean _baseMappingInitialized= false; + private boolean _hasSignature = false; + + static + { + List propertyList = new ArrayList(8); + createPropertyList(CalloutMappingDeclaration.class, propertyList); + addProperty(JAVADOC_PROPERTY, propertyList); + addProperty(ROLE_MAPPING_ELEMENT_PROPERTY, propertyList); + addProperty(BINDING_OPERATOR_PROPERTY, propertyList); + addProperty(BASE_MAPPING_ELEMENT_PROPERTY, propertyList); + addProperty(SIGNATURE_PROPERTY, propertyList); + addProperty(PARAMETER_MAPPINGS_PROPERTY, propertyList); + addProperty(MODIFIERS_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS_2_0 = reapPropertyList(propertyList); + + propertyList = new ArrayList(8); + createPropertyList(CalloutMappingDeclaration.class, propertyList); + addProperty(JAVADOC_PROPERTY, propertyList); + addProperty(ROLE_MAPPING_ELEMENT_PROPERTY, propertyList); + addProperty(BINDING_OPERATOR_PROPERTY, propertyList); + addProperty(BASE_MAPPING_ELEMENT_PROPERTY, propertyList); + addProperty(SIGNATURE_PROPERTY, propertyList); + addProperty(PARAMETER_MAPPINGS_PROPERTY, propertyList); + addProperty(MODIFIERS2_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS_3_0 = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the AST.JLS* constants + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + */ + public static List propertyDescriptors(int apiLevel) + { + if(apiLevel == AST.JLS3) + return PROPERTY_DESCRIPTORS_3_0; + else + return PROPERTY_DESCRIPTORS_2_0; + } + + final SimplePropertyDescriptor internalModifiersProperty() + { + return MODIFIERS_PROPERTY; + } + + final ChildListPropertyDescriptor internalModifiers2Property() + { + return MODIFIERS2_PROPERTY; + } + + final ChildListPropertyDescriptor internalParameterMappingsProperty() + { + return PARAMETER_MAPPINGS_PROPERTY; + } + + ChildPropertyDescriptor internalJavadocProperty() + { + return JAVADOC_PROPERTY; + } + + ChildPropertyDescriptor internalGetRoleElementProperty() { + return ROLE_MAPPING_ELEMENT_PROPERTY; + } + + ChildPropertyDescriptor internalGetBindingOperatorProperty() { + return BINDING_OPERATOR_PROPERTY; + } + + final int internalGetSetIntProperty(SimplePropertyDescriptor property, boolean isGetRequest, int value) + { + if (property == MODIFIERS_PROPERTY) + { + if (isGetRequest) + { + return getModifiers(); + } + else + { + setModifiers(value); + return 0; + } + } + // allow default implementation to flag the error + return super.internalGetSetIntProperty(property, isGetRequest, value); + } + + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean isGet, ASTNode child) + { + if (property == JAVADOC_PROPERTY) + { + if (isGet) + { + return getJavadoc(); + } + else + { + setJavadoc((Javadoc) child); + return null; + } + } + + if (property == BASE_MAPPING_ELEMENT_PROPERTY) + { + if (isGet) + { + return getBaseMappingElement(); + } + else + { + setBaseMappingElement((MethodSpec) child); + return null; + } + } + // allow default implementation to flag the error (incl. handling of elements common to all method mappings): + return super.internalGetSetChildProperty(property, isGet, child); + } + + final boolean internalGetSetBooleanProperty(SimplePropertyDescriptor property, boolean get, boolean value) + { + if (property == SIGNATURE_PROPERTY) + { + if (get) + { + return hasSignature(); + } + else + { + setSignatureFlag(value); + return false; + } + } + return super.internalGetSetBooleanProperty(property, get, value); + } + + final List internalGetChildListProperty(ChildListPropertyDescriptor property) + { + if (property == PARAMETER_MAPPINGS_PROPERTY) + { + return getParameterMappings(); + } + if (property == MODIFIERS2_PROPERTY) + { + return modifiers(); + } + + // allow default implementation to flag the error + return super.internalGetChildListProperty(property); + } + + List internalStructuralPropertiesForType(int apiLevel) + { + return propertyDescriptors(apiLevel); + } + + int getNodeType0() + { + return CALLOUT_MAPPING_DECLARATION; + } + + @SuppressWarnings("unchecked") + ASTNode clone0(AST target) + { + CalloutMappingDeclaration result = new CalloutMappingDeclaration(target); + if (this.ast.apiLevel >= AST.JLS3) + result.modifiers().addAll(ASTNode.copySubtrees(target, modifiers())); // annotations + result.setSourceRange(this.getStartPosition(), this.getLength()); + result.setJavadoc( + (Javadoc) ASTNode.copySubtree(target, getJavadoc())); + result.setRoleMappingElement( + (MethodMappingElement) ASTNode.copySubtree(target, getRoleMappingElement())); + result.setBindingOperator((MethodBindingOperator)bindingOperator().clone(target)); + result.setBaseMappingElement( + (MethodMappingElement) ASTNode.copySubtree(target, getBaseMappingElement())); + result.setSignatureFlag(this.hasSignature()); + result.getParameterMappings().addAll( + ASTNode.copySubtrees(target, this.getParameterMappings())); + + return result; + } + + boolean subtreeMatch0(ASTMatcher matcher, Object other) + { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + void accept0(ASTVisitor visitor) + { + boolean visitChildren = visitor.visit(this); + if (visitChildren) + { + // visit children in normal left to right reading order + acceptChild(visitor, getJavadoc()); + if (this.ast.apiLevel >= AST.JLS3) + acceptChildren(visitor, modifiers); + acceptChild(visitor, roleMappingElement); + acceptChild(visitor, bindingOperator); + acceptChild(visitor, _baseMappingElement); + acceptChildren(visitor,_parameterMappings); + } + visitor.endVisit(this); + } + + int treeSize() + { + return memSize() + (super.optionalDocComment == null + ? 0 + : getJavadoc().treeSize()); + } + + /** + * Returns the method spec right of the callout arrow. + * @return the right method spec, i.e. the referenced base method + * @see Modifier + */ + public MethodMappingElement getBaseMappingElement() + { + if (_baseMappingElement == null && !this._baseMappingInitialized) + { + // lazy init must be thread-safe for readers + synchronized (this) + { + if (_baseMappingElement == null) + { + preLazyInit(); + _baseMappingElement = new MethodSpec(this.ast); + this._baseMappingInitialized= true; + postLazyInit(_baseMappingElement, BASE_MAPPING_ELEMENT_PROPERTY); + } + } + } + return _baseMappingElement; + } + + /** + * Sets the right method spec (base method spec) declared in this callout + * mapping declaration to the given method spec. + * + * @param baseMappingElement + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public void setBaseMappingElement(MethodMappingElement baseMappingElement) + { + this._baseMappingInitialized= true; + ASTNode oldChild = _baseMappingElement; + preReplaceChild(oldChild, baseMappingElement, BASE_MAPPING_ELEMENT_PROPERTY); + _baseMappingElement = baseMappingElement; + postReplaceChild(oldChild, baseMappingElement, BASE_MAPPING_ELEMENT_PROPERTY); + } + + /** + * + * @return the flag, whether callout is a callout override or a simple callout + * true, if an override; + */ + public boolean isCalloutOverride() + { + return this.bindingOperator().getBindingKind() == MethodBindingOperator.KIND_CALLOUT_OVERRIDE; + } + + public boolean hasSignature() + { + return _hasSignature; + } + + public void setSignatureFlag(boolean hasSignature) + { + preValueChange(SIGNATURE_PROPERTY); + _hasSignature = hasSignature; + postValueChange(SIGNATURE_PROPERTY); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CastExpression.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CastExpression.java new file mode 100644 index 000000000..6e1f5485e --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CastExpression.java @@ -0,0 +1,264 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Cast expression AST node type. + * + * <pre> + * CastExpression: + * <b>(</b> Type <b>)</b> Expression + * </pre> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class CastExpression extends Expression { + + /** + * The "type" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor TYPE_PROPERTY = + new ChildPropertyDescriptor(CastExpression.class, "type", Type.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "expression" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor EXPRESSION_PROPERTY = + new ChildPropertyDescriptor(CastExpression.class, "expression", Expression.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List properyList = new ArrayList(3); + createPropertyList(CastExpression.class, properyList); + addProperty(TYPE_PROPERTY, properyList); + addProperty(EXPRESSION_PROPERTY, properyList); + PROPERTY_DESCRIPTORS = reapPropertyList(properyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The type; lazily initialized; defaults to a unspecified, + * legal type. + */ + private Type type = null; + + /** + * The expression; lazily initialized; defaults to a unspecified, but legal, + * expression. + */ + private Expression expression = null; + + /** + * Creates a new AST node for a cast expression owned by the given + * AST. By default, the type and expression are unspecified (but legal). + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + CastExpression(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == EXPRESSION_PROPERTY) { + if (get) { + return getExpression(); + } else { + setExpression((Expression) child); + return null; + } + } + if (property == TYPE_PROPERTY) { + if (get) { + return getType(); + } else { + setType((Type) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return CAST_EXPRESSION; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + CastExpression result = new CastExpression(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setType((Type) getType().clone(target)); + result.setExpression((Expression) getExpression().clone(target)); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + acceptChild(visitor, getType()); + acceptChild(visitor, getExpression()); + } + visitor.endVisit(this); + } + + /** + * Returns the type in this cast expression. + * + * @return the type + */ + public Type getType() { + if (this.type == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.type == null) { + preLazyInit(); + this.type = this.ast.newPrimitiveType(PrimitiveType.INT); + postLazyInit(this.type, TYPE_PROPERTY); + } + } + } + return this.type; + } + + /** + * Sets the type in this cast expression to the given type. + * + * @param type the new type + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public void setType(Type type) { + if (type == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.type; + preReplaceChild(oldChild, type, TYPE_PROPERTY); + this.type = type; + postReplaceChild(oldChild, type, TYPE_PROPERTY); + } + + /** + * Returns the expression of this cast expression. + * + * @return the expression node + */ + public Expression getExpression() { + if (this.expression == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.expression == null) { + preLazyInit(); + this.expression = new SimpleName(this.ast); + postLazyInit(this.expression, EXPRESSION_PROPERTY); + } + } + } + return this.expression; + } + + /** + * Sets the expression of this cast expression. + * + * @param expression the new expression node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setExpression(Expression expression) { + if (expression == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.expression; + preReplaceChild(oldChild, expression, EXPRESSION_PROPERTY); + this.expression = expression; + postReplaceChild(oldChild, expression, EXPRESSION_PROPERTY); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + // treat Code as free + return BASE_NODE_SIZE + 2 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.expression == null ? 0 : getExpression().treeSize()) + + (this.type == null ? 0 : getType().treeSize()); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CatchClause.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CatchClause.java new file mode 100644 index 000000000..e9a312f41 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CatchClause.java @@ -0,0 +1,267 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Catch clause AST node type. + * + * <pre> + * CatchClause: + * <b>catch</b> <b>(</b> FormalParameter <b>)</b> Block + * </pre> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class CatchClause extends ASTNode { + + /** + * The "exception" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor EXCEPTION_PROPERTY = + new ChildPropertyDescriptor(CatchClause.class, "exception", SingleVariableDeclaration.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "body" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor BODY_PROPERTY = + new ChildPropertyDescriptor(CatchClause.class, "body", Block.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List properyList = new ArrayList(3); + createPropertyList(CatchClause.class, properyList); + addProperty(EXCEPTION_PROPERTY, properyList); + addProperty(BODY_PROPERTY, properyList); + PROPERTY_DESCRIPTORS = reapPropertyList(properyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The body; lazily initialized; defaults to an empty block. + */ + private Block body = null; + + /** + * The exception variable declaration; lazily initialized; defaults to a + * unspecified, but legal, variable declaration. + */ + private SingleVariableDeclaration exceptionDecl = null; + + /** + * Creates a new AST node for a catch clause owned by the given + * AST. By default, the catch clause declares an unspecified, but legal, + * exception declaration and has an empty block. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + CatchClause(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == EXCEPTION_PROPERTY) { + if (get) { + return getException(); + } else { + setException((SingleVariableDeclaration) child); + return null; + } + } + if (property == BODY_PROPERTY) { + if (get) { + return getBody(); + } else { + setBody((Block) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return CATCH_CLAUSE; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + CatchClause result = new CatchClause(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setBody((Block) getBody().clone(target)); + result.setException( + (SingleVariableDeclaration) ASTNode.copySubtree(target, getException())); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + acceptChild(visitor, getException()); + acceptChild(visitor, getBody()); + } + visitor.endVisit(this); + } + + /** + * Returns the exception variable declaration of this catch clause. + * + * @return the exception variable declaration node + */ + public SingleVariableDeclaration getException() { + if (this.exceptionDecl == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.exceptionDecl == null) { + preLazyInit(); + this.exceptionDecl = new SingleVariableDeclaration(this.ast); + postLazyInit(this.exceptionDecl, EXCEPTION_PROPERTY); + } + } + } + return this.exceptionDecl; + } + + /** + * Sets the variable declaration of this catch clause. + * + * @param exception the exception variable declaration node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setException(SingleVariableDeclaration exception) { + if (exception == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.exceptionDecl; + preReplaceChild(oldChild, exception, EXCEPTION_PROPERTY); + this.exceptionDecl= exception; + postReplaceChild(oldChild, exception, EXCEPTION_PROPERTY); + } + + /** + * Returns the body of this catch clause. + * + * @return the catch clause body + */ + public Block getBody() { + if (this.body == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.body == null) { + preLazyInit(); + this.body = new Block(this.ast); + postLazyInit(this.body, BODY_PROPERTY); + } + } + } + return this.body; + } + + /** + * Sets the body of this catch clause. + * + * @param body the catch clause block node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setBody(Block body) { + if (body == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.body; + preReplaceChild(oldChild, body, BODY_PROPERTY); + this.body = body; + postReplaceChild(oldChild, body, BODY_PROPERTY); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + // treat Code as free + return BASE_NODE_SIZE + 2 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.exceptionDecl == null ? 0 : getException().treeSize()) + + (this.body == null ? 0 : getBody().treeSize()); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CharacterLiteral.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CharacterLiteral.java new file mode 100644 index 000000000..ebf8c9b71 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CharacterLiteral.java @@ -0,0 +1,389 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jdt.core.compiler.InvalidInputException; +import org.eclipse.jdt.internal.compiler.parser.Scanner; +import org.eclipse.jdt.internal.compiler.parser.ScannerHelper; +import org.eclipse.jdt.internal.compiler.parser.TerminalTokens; + +/** + * Character literal nodes. + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class CharacterLiteral extends Expression { + + /** + * The "escapedValue" structural property of this node type. + * @since 3.0 + */ + public static final SimplePropertyDescriptor ESCAPED_VALUE_PROPERTY = + new SimplePropertyDescriptor(CharacterLiteral.class, "escapedValue", String.class, MANDATORY); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List properyList = new ArrayList(2); + createPropertyList(CharacterLiteral.class, properyList); + addProperty(ESCAPED_VALUE_PROPERTY, properyList); + PROPERTY_DESCRIPTORS = reapPropertyList(properyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The literal string, including quotes and escapes; defaults to the + * literal for the character 'X'. + */ + private String escapedValue = "\'X\'";//$NON-NLS-1$ + + /** + * Creates a new unparented character literal node owned by the given AST. + * By default, the character literal denotes an unspecified character. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + CharacterLiteral(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final Object internalGetSetObjectProperty(SimplePropertyDescriptor property, boolean get, Object value) { + if (property == ESCAPED_VALUE_PROPERTY) { + if (get) { + return getEscapedValue(); + } else { + setEscapedValue((String) value); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetObjectProperty(property, get, value); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return CHARACTER_LITERAL; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + CharacterLiteral result = new CharacterLiteral(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setEscapedValue(getEscapedValue()); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + visitor.visit(this); + visitor.endVisit(this); + } + + /** + * Returns the string value of this literal node. The value is the sequence + * of characters that would appear in the source program, including + * enclosing single quotes and embedded escapes. + * + * @return the escaped string value, including enclosing single quotes + * and embedded escapes + */ + public String getEscapedValue() { + return this.escapedValue; + } + + /** + * Sets the string value of this literal node. The value is the sequence + * of characters that would appear in the source program, including + * enclosing single quotes and embedded escapes. For example, + * <ul> + * <li><code>'a'</code> <code>setEscapedValue("\'a\'")</code></li> + * <li><code>'\n'</code> <code>setEscapedValue("\'\\n\'")</code></li> + * </ul> + * + * @param value the string value, including enclosing single quotes + * and embedded escapes + * @exception IllegalArgumentException if the argument is incorrect + */ + public void setEscapedValue(String value) { + // check setInternalEscapedValue(String) if this method is changed + if (value == null) { + throw new IllegalArgumentException(); + } + Scanner scanner = this.ast.scanner; + char[] source = value.toCharArray(); + scanner.setSource(source); + scanner.resetTo(0, source.length); + try { + int tokenType = scanner.getNextToken(); + switch(tokenType) { + case TerminalTokens.TokenNameCharacterLiteral: + break; + default: + throw new IllegalArgumentException(); + } + } catch(InvalidInputException e) { + throw new IllegalArgumentException(); + } + preValueChange(ESCAPED_VALUE_PROPERTY); + this.escapedValue = value; + postValueChange(ESCAPED_VALUE_PROPERTY); + } + + + /* (omit javadoc for this method) + * This method is a copy of setEscapedValue(String) that doesn't do any validation. + */ + void internalSetEscapedValue(String value) { + preValueChange(ESCAPED_VALUE_PROPERTY); + this.escapedValue = value; + postValueChange(ESCAPED_VALUE_PROPERTY); + } + + /** + * Returns the value of this literal node. + * <p> + * For example, + * <pre> + * CharacterLiteral s; + * s.setEscapedValue("\'x\'"); + * assert s.charValue() == 'x'; + * </pre> + * </p> + * + * @return the character value without enclosing quotes and embedded + * escapes + * @exception IllegalArgumentException if the literal value cannot be converted + */ + public char charValue() { + Scanner scanner = this.ast.scanner; + char[] source = this.escapedValue.toCharArray(); + scanner.setSource(source); + scanner.resetTo(0, source.length); + int firstChar = scanner.getNextChar(); + int secondChar = scanner.getNextChar(); + + if (firstChar == -1 || firstChar != '\'') { + throw new IllegalArgumentException("illegal character literal");//$NON-NLS-1$ + } + char value = (char) secondChar; + int nextChar = scanner.getNextChar(); + if (secondChar == '\\') { + if (nextChar == -1) { + throw new IllegalArgumentException("illegal character literal");//$NON-NLS-1$ + } + switch(nextChar) { + case 'b' : + value = '\b'; + break; + case 't' : + value = '\t'; + break; + case 'n' : + value = '\n'; + break; + case 'f' : + value = '\f'; + break; + case 'r' : + value = '\r'; + break; + case '\"': + value = '\"'; + break; + case '\'': + value = '\''; + break; + case '\\': + value = '\\'; + break; + default : //octal (well-formed: ended by a ' ) + try { + if (ScannerHelper.isDigit((char) nextChar)) { + int number = ScannerHelper.getNumericValue((char) nextChar); + nextChar = scanner.getNextChar(); + if (nextChar == -1) { + throw new IllegalArgumentException("illegal character literal");//$NON-NLS-1$ + } + if (nextChar != '\'') { + if (!ScannerHelper.isDigit((char) nextChar)) { + throw new IllegalArgumentException("illegal character literal");//$NON-NLS-1$ + } + number = (number * 8) + ScannerHelper.getNumericValue((char) nextChar); + nextChar = scanner.getNextChar(); + if (nextChar == -1) { + throw new IllegalArgumentException("illegal character literal");//$NON-NLS-1$ + } + if (nextChar != '\'') { + if (!ScannerHelper.isDigit((char) nextChar)) { + throw new IllegalArgumentException("illegal character literal");//$NON-NLS-1$ + } + number = (number * 8) + ScannerHelper.getNumericValue((char) nextChar); + } + } + return (char) number; + } else { + throw new IllegalArgumentException("illegal character literal");//$NON-NLS-1$ + } + } catch (InvalidInputException e) { + throw new IllegalArgumentException("illegal character literal");//$NON-NLS-1$ + } + } + nextChar = scanner.getNextChar(); + if (nextChar == -1) { + throw new IllegalArgumentException("illegal character literal");//$NON-NLS-1$ + } + } + if (nextChar == -1 || nextChar != '\'') { + throw new IllegalArgumentException("illegal character literal");//$NON-NLS-1$ + } + return value; + } + /** + * Sets the value of this character literal node to the given character. + * <p> + * For example, + * <pre> + * CharacterLiteral s; + * s.setCharValue('x'); + * assert s.charValue() == 'x'; + * assert s.getEscapedValue().equals("\'x\'"); + * </pre> + * </p> + * + * @param value the character value + */ + public void setCharValue(char value) { + StringBuffer b = new StringBuffer(3); + + b.append('\''); // opening delimiter + switch(value) { + case '\b' : + b.append("\\b"); //$NON-NLS-1$ + break; + case '\t' : + b.append("\\t"); //$NON-NLS-1$ + break; + case '\n' : + b.append("\\n"); //$NON-NLS-1$ + break; + case '\f' : + b.append("\\f"); //$NON-NLS-1$ + break; + case '\r' : + b.append("\\r"); //$NON-NLS-1$ + break; + case '\"': + b.append("\\\""); //$NON-NLS-1$ + break; + case '\'': + b.append("\\\'"); //$NON-NLS-1$ + break; + case '\\': + b.append("\\\\"); //$NON-NLS-1$ + break; + case '\0' : + b.append("\\0"); //$NON-NLS-1$ + break; + case '\1' : + b.append("\\1"); //$NON-NLS-1$ + break; + case '\2' : + b.append("\\2"); //$NON-NLS-1$ + break; + case '\3' : + b.append("\\3"); //$NON-NLS-1$ + break; + case '\4' : + b.append("\\4"); //$NON-NLS-1$ + break; + case '\5' : + b.append("\\5"); //$NON-NLS-1$ + break; + case '\6' : + b.append("\\6"); //$NON-NLS-1$ + break; + case '\7' : + b.append("\\7"); //$NON-NLS-1$ + break; + default: + b.append(value); + } + b.append('\''); // closing delimiter + setEscapedValue(b.toString()); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + int size = BASE_NODE_SIZE + 1 * 4 + stringSize(this.escapedValue); + return size; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return memSize(); + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ChildListPropertyDescriptor.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ChildListPropertyDescriptor.java new file mode 100644 index 000000000..b55cfe972 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ChildListPropertyDescriptor.java @@ -0,0 +1,98 @@ +/******************************************************************************* + * Copyright (c) 2004, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.dom; + +/** + * Descriptor for a child list property of an AST node. + * A child list property is one whose value is a list of + * {@link ASTNode}. + * + * @see org.eclipse.jdt.core.dom.ASTNode#getStructuralProperty(StructuralPropertyDescriptor) + * @since 3.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public final class ChildListPropertyDescriptor extends StructuralPropertyDescriptor { + + /** + * Element type. For example, for a node type like + * CompilationUnit, the "imports" property is ImportDeclaration.class. + * <p> + * Field is private, but marked package-visible for fast + * access from ASTNode. + * </p> + */ + final Class elementType; + + /** + * Indicates whether a cycle is possible. + * <p> + * Field is private, but marked package-visible for fast + * access from ASTNode. + * </p> + */ + final boolean cycleRisk; + + /** + * Creates a new child list property descriptor with the given property id. + * Note that this constructor is declared package-private so that + * property descriptors can only be created by the AST + * implementation. + * + * @param nodeClass concrete AST node type that owns this property + * @param propertyId the property id + * @param elementType the element type of this property + * @param cycleRisk <code>true</code> if this property is at + * risk of cycles, and <code>false</code> if there is no worry about cycles + */ + ChildListPropertyDescriptor(Class nodeClass, String propertyId, Class elementType, boolean cycleRisk) { + super(nodeClass, propertyId); + if (elementType == null) { + throw new IllegalArgumentException(); + } + this.elementType = elementType; + this.cycleRisk = cycleRisk; + } + + /** + * Returns the element type of this list property. + * <p> + * For example, for a node type like CompilationUnit, + * the "imports" property returns <code>ImportDeclaration.class</code>. + * </p> + * + * @return the element type of the property + */ + public final Class getElementType() { + return this.elementType; + } + + /** + * Returns whether this property is vulnerable to cycles. + * <p> + * A property is vulnerable to cycles if a node of the owning + * type (that is, the type that owns this property) could legally + * appear in the AST subtree below this property. For example, + * the body property of a + * {@link MethodDeclaration} node + * admits a body which might include statement that embeds + * another {@link MethodDeclaration} node. + * On the other hand, the name property of a + * MethodDeclaration node admits only names, and thereby excludes + * another MethodDeclaration node. + * </p> + * + * @return <code>true</code> if cycles are possible, + * and <code>false</code> if cycles are impossible + */ + public final boolean cycleRisk() { + return this.cycleRisk; + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ChildPropertyDescriptor.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ChildPropertyDescriptor.java new file mode 100644 index 000000000..2e6a8a288 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ChildPropertyDescriptor.java @@ -0,0 +1,113 @@ +/******************************************************************************* + * Copyright (c) 2004, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.dom; + +/** + * Descriptor for a child property of an AST node. + * A child property is one whose value is an + * {@link ASTNode}. + * + * @see org.eclipse.jdt.core.dom.ASTNode#getStructuralProperty(StructuralPropertyDescriptor) + * @see org.eclipse.jdt.core.dom.ASTNode#setStructuralProperty(StructuralPropertyDescriptor, Object) + * @since 3.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public final class ChildPropertyDescriptor extends StructuralPropertyDescriptor { + + /** + * Child type. For example, for a node type like + * CompilationUnit, the "package" property is PackageDeclaration.class + */ + private final Class childClass; + + /** + * Indicates whether the child is mandatory. A child property is allowed + * to be <code>null</code> only if it is not mandatory. + */ + private final boolean mandatory; + + /** + * Indicates whether a cycle is possible. + * Field is private, but marked package-visible for fast + * access from ASTNode. + */ + final boolean cycleRisk; + + /** + * Creates a new child property descriptor with the given property id. + * Note that this constructor is declared package-private so that + * property descriptors can only be created by the AST + * implementation. + * + * @param nodeClass concrete AST node type that owns this property + * @param propertyId the property id + * @param childType the child type of this property + * @param mandatory <code>true</code> if the property is mandatory, + * and <code>false</code> if it is may be <code>null</code> + * @param cycleRisk <code>true</code> if this property is at + * risk of cycles, and <code>false</code> if there is no worry about cycles + */ + ChildPropertyDescriptor(Class nodeClass, String propertyId, Class childType, boolean mandatory, boolean cycleRisk) { + super(nodeClass, propertyId); + if (childType == null || !ASTNode.class.isAssignableFrom(childType)) { + throw new IllegalArgumentException(); + } + this.childClass = childType; + this.mandatory = mandatory; + this.cycleRisk = cycleRisk; + } + + /** + * Returns the child type of this property. + * <p> + * For example, for a node type like CompilationUnit, + * the "package" property returns <code>PackageDeclaration.class</code>. + * </p> + * + * @return the child type of the property + */ + public final Class getChildType() { + return this.childClass; + } + + /** + * Returns whether this property is mandatory. A property value + * is not allowed to be <code>null</code> if it is mandatory. + * + * @return <code>true</code> if the property is mandatory, + * and <code>false</code> if it is may be <code>null</code> + */ + public final boolean isMandatory() { + return this.mandatory; + } + + /** + * Returns whether this property is vulnerable to cycles. + * <p> + * A property is vulnerable to cycles if a node of the owning + * type (that is, the type that owns this property) could legally + * appear in the AST subtree below this property. For example, + * the body property of a + * {@link MethodDeclaration} node + * admits a body which might include statement that embeds + * another {@link MethodDeclaration} node. + * On the other hand, the name property of a + * MethodDeclaration node admits only names, and thereby excludes + * another MethodDeclaration node. + * </p> + * + * @return <code>true</code> if cycles are possible, + * and <code>false</code> if cycles are impossible + */ + public final boolean cycleRisk() { + return this.cycleRisk; + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ClassInstanceCreation.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ClassInstanceCreation.java new file mode 100644 index 000000000..9d8e42750 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ClassInstanceCreation.java @@ -0,0 +1,585 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Class instance creation expression AST node type. + * For JLS2: + * <pre> + * ClassInstanceCreation: + * [ Expression <b>.</b> ] <b>new</b> Name + * <b>(</b> [ Expression { <b>,</b> Expression } ] <b>)</b> + * [ AnonymousClassDeclaration ] + * </pre> + * For JLS3, type arguments are added + * and the type name is generalized to a type so that parameterized + * types can be instantiated: + * <pre> + * ClassInstanceCreation: + * [ Expression <b>.</b> ] + * <b>new</b> [ <b><</b> Type { <b>,</b> Type } <b>></b> ] + * Type <b>(</b> [ Expression { <b>,</b> Expression } ] <b>)</b> + * [ AnonymousClassDeclaration ] + * </pre> + * <p> + * Not all node arragements will represent legal Java constructs. In particular, + * it is nonsense if the type is a primitive type or an array type (primitive + * types cannot be instantiated, and array creations must be represented with + * <code>ArrayCreation</code> nodes). The normal use is when the type is a + * simple, qualified, or parameterized type. + * </p> + * <p> + * A type like "A.B" can be represented either of two ways: + * <ol> + * <li> + * <code>QualifiedType(SimpleType(SimpleName("A")),SimpleName("B"))</code> + * </li> + * <li> + * <code>SimpleType(QualifiedName(SimpleName("A"),SimpleName("B")))</code> + * </li> + * </ol> + * The first form is preferred when "A" is known to be a type (as opposed + * to a package). However, a parser cannot always determine this. Clients + * should be prepared to handle either rather than make assumptions. + * (Note also that the first form became possible as of JLS3; only the second + * form existed in JLS2.) + * </p> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class ClassInstanceCreation extends Expression { + + /** + * The "typeArguments" structural property of this node type (added in JLS3 API). + * @since 3.1 + */ + public static final ChildListPropertyDescriptor TYPE_ARGUMENTS_PROPERTY = + new ChildListPropertyDescriptor(ClassInstanceCreation.class, "typeArguments", Type.class, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "expression" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor EXPRESSION_PROPERTY = + new ChildPropertyDescriptor(ClassInstanceCreation.class, "expression", Expression.class, OPTIONAL, CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "name" structural property of this node type (JLS2 API only). + * @since 3.0 + */ + public static final ChildPropertyDescriptor NAME_PROPERTY = + new ChildPropertyDescriptor(ClassInstanceCreation.class, "name", Name.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "type" structural property of this node type (added in JLS3 API). + * @since 3.1 + */ + public static final ChildPropertyDescriptor TYPE_PROPERTY = + new ChildPropertyDescriptor(ClassInstanceCreation.class, "type", Type.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "arguments" structural property of this node type. + * @since 3.0 + */ + public static final ChildListPropertyDescriptor ARGUMENTS_PROPERTY = + new ChildListPropertyDescriptor(ClassInstanceCreation.class, "arguments", Expression.class, CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "anonymousClassDeclaration" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor ANONYMOUS_CLASS_DECLARATION_PROPERTY = + new ChildPropertyDescriptor(ClassInstanceCreation.class, "anonymousClassDeclaration", AnonymousClassDeclaration.class, OPTIONAL, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + * @since 3.0 + */ + private static final List PROPERTY_DESCRIPTORS_2_0; + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + * @since 3.1 + */ + private static final List PROPERTY_DESCRIPTORS_3_0; + + static { + List properyList = new ArrayList(5); + createPropertyList(ClassInstanceCreation.class, properyList); + addProperty(EXPRESSION_PROPERTY, properyList); + addProperty(NAME_PROPERTY, properyList); + addProperty(ARGUMENTS_PROPERTY, properyList); + addProperty(ANONYMOUS_CLASS_DECLARATION_PROPERTY, properyList); + PROPERTY_DESCRIPTORS_2_0 = reapPropertyList(properyList); + + properyList = new ArrayList(6); + createPropertyList(ClassInstanceCreation.class, properyList); + addProperty(EXPRESSION_PROPERTY, properyList); + addProperty(TYPE_ARGUMENTS_PROPERTY, properyList); + addProperty(TYPE_PROPERTY, properyList); + addProperty(ARGUMENTS_PROPERTY, properyList); + addProperty(ANONYMOUS_CLASS_DECLARATION_PROPERTY, properyList); + PROPERTY_DESCRIPTORS_3_0 = reapPropertyList(properyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + if (apiLevel == AST.JLS2_INTERNAL) { + return PROPERTY_DESCRIPTORS_2_0; + } else { + return PROPERTY_DESCRIPTORS_3_0; + } + } + + /** + * The optional expression; <code>null</code> for none; defaults to none. + */ + private Expression optionalExpression = null; + + /** + * The type arguments (element type: <code>Type</code>). + * Null in JLS2. Added in JLS3; defaults to an empty list + * (see constructor). + * @since 3.1 + */ + private ASTNode.NodeList typeArguments = null; + + /** + * The type name; lazily initialized; defaults to a unspecified, + * legal type name. Not used in JLS3. + */ + private Name typeName = null; + + /** + * The type; lazily initialized; defaults to a unspecified type. + * @since 3.0 + */ + private Type type = null; + + /** + * The list of argument expressions (element type: + * <code>Expression</code>). Defaults to an empty list. + */ + private ASTNode.NodeList arguments = + new ASTNode.NodeList(ARGUMENTS_PROPERTY); + + /** + * The optional anonymous class declaration; <code>null</code> for none; + * defaults to none. + */ + private AnonymousClassDeclaration optionalAnonymousClassDeclaration = null; + + /** + * Creates a new AST node for a class instance creation expression owned + * by the given AST. By default, there is no qualifying expression, + * an empty list of type parameters, an unspecified type, an empty + * list of arguments, and does not declare an anonymous class. + * <p> + * N.B. This constructor is package-private; all subclasses must be + * declared in the same package; clients are unable to declare + * additional subclasses. + * </p> + * + * @param ast the AST that is to own this node + */ + ClassInstanceCreation (AST ast) { + super(ast); + if (ast.apiLevel >= AST.JLS3) { + this.typeArguments = new ASTNode.NodeList(TYPE_ARGUMENTS_PROPERTY); + } + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + * @since 3.0 + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == EXPRESSION_PROPERTY) { + if (get) { + return getExpression(); + } else { + setExpression((Expression) child); + return null; + } + } + if (property == NAME_PROPERTY) { + if (get) { + return getName(); + } else { + setName((Name) child); + return null; + } + } + if (property == TYPE_PROPERTY) { + if (get) { + return getType(); + } else { + setType((Type) child); + return null; + } + } + if (property == ANONYMOUS_CLASS_DECLARATION_PROPERTY) { + if (get) { + return getAnonymousClassDeclaration(); + } else { + setAnonymousClassDeclaration((AnonymousClassDeclaration) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalGetChildListProperty(ChildListPropertyDescriptor property) { + if (property == ARGUMENTS_PROPERTY) { + return arguments(); + } + if (property == TYPE_ARGUMENTS_PROPERTY) { + return typeArguments(); + } + // allow default implementation to flag the error + return super.internalGetChildListProperty(property); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return CLASS_INSTANCE_CREATION; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + ClassInstanceCreation result = new ClassInstanceCreation(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setExpression( + (Expression) ASTNode.copySubtree(target, getExpression())); + if (this.ast.apiLevel == AST.JLS2_INTERNAL) { + result.setName((Name) getName().clone(target)); + } + if (this.ast.apiLevel >= AST.JLS3) { + result.typeArguments().addAll(ASTNode.copySubtrees(target, typeArguments())); + result.setType((Type) getType().clone(target)); + } + result.arguments().addAll(ASTNode.copySubtrees(target, arguments())); + result.setAnonymousClassDeclaration( + (AnonymousClassDeclaration) + ASTNode.copySubtree(target, getAnonymousClassDeclaration())); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + acceptChild(visitor, getExpression()); + if (this.ast.apiLevel == AST.JLS2_INTERNAL) { + acceptChild(visitor, getName()); + } + if (this.ast.apiLevel >= AST.JLS3) { + acceptChildren(visitor, this.typeArguments); + acceptChild(visitor, getType()); + } + acceptChildren(visitor, this.arguments); + acceptChild(visitor, getAnonymousClassDeclaration()); + } + visitor.endVisit(this); + } + + /** + * Returns the expression of this class instance creation expression, or + * <code>null</code> if there is none. + * + * @return the expression node, or <code>null</code> if there is none + */ + public Expression getExpression() { + return this.optionalExpression; + } + + /** + * Sets or clears the expression of this class instance creation expression. + * + * @param expression the expression node, or <code>null</code> if + * there is none + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setExpression(Expression expression) { + // a ClassInstanceCreation may occur inside an Expression + // must check cycles + ASTNode oldChild = this.optionalExpression; + preReplaceChild(oldChild, expression, EXPRESSION_PROPERTY); + this.optionalExpression = expression; + postReplaceChild(oldChild, expression, EXPRESSION_PROPERTY); + } + + /** + * Returns the live ordered list of type arguments of this class + * instance creation (added in JLS3 API). + * + * @return the live list of type arguments + * (element type: <code>Type</code>) + * @exception UnsupportedOperationException if this operation is used in + * a JLS2 AST + * @since 3.1 + */ + public List typeArguments() { + // more efficient than just calling unsupportedIn2() to check + if (this.typeArguments == null) { + unsupportedIn2(); + } + return this.typeArguments; + } + + /** + * Returns the name of the type instantiated in this class instance + * creation expression (JLS2 API only). + * + * @return the type name node + * @exception UnsupportedOperationException if this operation is used in + * an AST later than JLS2 + * @deprecated In the JLS3 API, this method is replaced by + * {@link #getType()}, which returns a <code>Type</code> instead of a + * <code>Name</code>. + */ + public Name getName() { + return internalGetName(); + } + + /** + * Internal synonym for deprecated method. Used to avoid + * deprecation warnings. + * @since 3.1 + */ + /*package*/ Name internalGetName() { + supportedOnlyIn2(); + if (this.typeName == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.typeName == null) { + preLazyInit(); + this.typeName = new SimpleName(this.ast); + postLazyInit(this.typeName, NAME_PROPERTY); + } + } + } + return this.typeName; + } + + /** + * Sets the name of the type instantiated in this class instance + * creation expression (JLS2 API only). + * + * @param name the new type name + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li>` + * </ul> + * @exception UnsupportedOperationException if this operation is used in + * an AST later than JLS2 + * @deprecated In the JLS3 API, this method is replaced by + * {@link #setType(Type)}, which expects a <code>Type</code> instead of + * a <code>Name</code>. + */ + public void setName(Name name) { + internalSetName(name); + } + + /** + * Internal synonym for deprecated method. Used to avoid + * deprecation warnings. + * @since 3.1 + */ + /*package*/ void internalSetName(Name name) { + supportedOnlyIn2(); + if (name == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.typeName; + preReplaceChild(oldChild, name, NAME_PROPERTY); + this.typeName = name; + postReplaceChild(oldChild, name, NAME_PROPERTY); + } + + /** + * Returns the type instantiated in this class instance creation + * expression (added in JLS3 API). + * + * @return the type node + * @exception UnsupportedOperationException if this operation is used in + * a JLS2 AST + * @since 3.1 + */ + public Type getType() { + unsupportedIn2(); + if (this.type == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.type == null) { + preLazyInit(); + this.type = new SimpleType(this.ast); + postLazyInit(this.type, TYPE_PROPERTY); + } + } + } + return this.type; + } + + /** + * Sets the type instantiated in this class instance creation + * expression (added in JLS3 API). + * + * @param type the new type + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li>` + * </ul> + * @exception UnsupportedOperationException if this operation is used in + * a JLS2 AST + * @since 3.1 + */ + public void setType(Type type) { + unsupportedIn2(); + if (type == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.type; + preReplaceChild(oldChild, type, TYPE_PROPERTY); + this.type = type; + postReplaceChild(oldChild, type, TYPE_PROPERTY); + } + + /** + * Returns the live ordered list of argument expressions in this class + * instance creation expression. + * + * @return the live list of argument expressions (possibly empty) + * (element type: <code>Expression</code>) + */ + public List arguments() { + return this.arguments; + } + + /** + * Returns the anonymous class declaration introduced by this + * class instance creation expression, if it has one. + * + * @return the anonymous class declaration, or <code>null</code> if none + */ + public AnonymousClassDeclaration getAnonymousClassDeclaration() { + return this.optionalAnonymousClassDeclaration; + } + + /** + * Sets whether this class instance creation expression declares + * an anonymous class (that is, has class body declarations). + * + * @param decl the anonymous class declaration, or <code>null</code> + * if none + */ + public void setAnonymousClassDeclaration(AnonymousClassDeclaration decl) { + ASTNode oldChild = this.optionalAnonymousClassDeclaration; + preReplaceChild(oldChild, decl, ANONYMOUS_CLASS_DECLARATION_PROPERTY); + this.optionalAnonymousClassDeclaration = decl; + postReplaceChild(oldChild, decl, ANONYMOUS_CLASS_DECLARATION_PROPERTY); + } + + /** + * Resolves and returns the binding for the constructor invoked by this + * expression. For anonymous classes, the binding is that of the anonymous + * constructor. + * <p> + * Note that bindings are generally unavailable unless requested when the + * AST is being built. + * </p> + * + * @return the constructor binding, or <code>null</code> if the binding + * cannot be resolved + */ + public IMethodBinding resolveConstructorBinding() { + return this.ast.getBindingResolver().resolveConstructor(this); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + // treat Code as free + return BASE_NODE_SIZE + 6 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + // n.b. type == null for ast.API_LEVEL == JLS2 + // n.b. typeArguments == null for ast.API_LEVEL == JLS2 + // n.b. typeName == null for ast.API_LEVEL >= JLS3 + return + memSize() + + (this.typeName == null ? 0 : getName().treeSize()) + + (this.type == null ? 0 : getType().treeSize()) + + (this.optionalExpression == null ? 0 : getExpression().treeSize()) + + (this.typeArguments == null ? 0 : this.typeArguments.listSize()) + + (this.arguments == null ? 0 : this.arguments.listSize()) + + (this.optionalAnonymousClassDeclaration == null ? 0 : getAnonymousClassDeclaration().treeSize()); + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Comment.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Comment.java new file mode 100644 index 000000000..ca69b46e5 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Comment.java @@ -0,0 +1,129 @@ +/******************************************************************************* + * Copyright (c) 2004, 2009 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.dom; + +/** + * Abstract base class for all AST nodes that represent comments. + * There are exactly three kinds of comment: + * line comments ({@link LineComment}), + * block comments ({@link BlockComment}), and + * doc comments ({@link Javadoc}). + * <p> + * <pre> + * Comment: + * LineComment + * BlockComment + * Javadoc + * </pre> + * </p> + * + * @since 3.0 + */ +public abstract class Comment extends ASTNode { + + /** + * Alternate root node, or <code>null</code> if none. + * Initially <code>null</code>. + */ + private ASTNode alternateRoot = null; + + /** + * Creates a new AST node for a comment owned by the given AST. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + Comment(AST ast) { + super(ast); + } + + /** + * Returns whether this comment is a block comment + * (<code>BlockComment</code>). + * + * @return <code>true</code> if this is a block comment, and + * <code>false</code> otherwise + */ + public final boolean isBlockComment() { + return (this instanceof BlockComment); + } + + /** + * Returns whether this comment is a line comment + * (<code>LineComment</code>). + * + * @return <code>true</code> if this is a line comment, and + * <code>false</code> otherwise + */ + public final boolean isLineComment() { + return (this instanceof LineComment); + } + + /** + * Returns whether this comment is a doc comment + * (<code>Javadoc</code>). + * + * @return <code>true</code> if this is a doc comment, and + * <code>false</code> otherwise + */ + public final boolean isDocComment() { + return (this instanceof Javadoc); + } + + /** + * Returns the root AST node that this comment occurs + * within, or <code>null</code> if none (or not recorded). + * <p> + * Typically, the comment nodes created while parsing a compilation + * unit are not considered descendents of the normal AST + * root, namely an {@link CompilationUnit}. Instead, these + * comment nodes exist outside the normal AST and each is + * a root in its own right. This optional property provides + * a well-known way to navigate from the comment to the + * compilation unit in such cases. Note that the alternate root + * property is not one of the comment node's children. It is simply a + * reference to a node. + * </p> + * + * @return the alternate root node, or <code>null</code> + * if none + * @see #setAlternateRoot(ASTNode) + */ + public final ASTNode getAlternateRoot() { + return this.alternateRoot; + } + + /** + * Returns the root AST node that this comment occurs + * within, or <code>null</code> if none (or not recorded). + * <p> + * </p> + * + * @param root the alternate root node, or <code>null</code> + * if none + * @see #getAlternateRoot() + */ + public final void setAlternateRoot(ASTNode root) { + // alternate root is *not* considered a structural property + // but we protect them nevertheless + checkModifiable(); + this.alternateRoot = root; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return BASE_NODE_SIZE + 1 * 4; + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CompilationUnit.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CompilationUnit.java new file mode 100644 index 000000000..ec7a585cd --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CompilationUnit.java @@ -0,0 +1,1091 @@ +/******************************************************************************* + * Copyright (c) 2000, 2009 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.core.ITypeRoot; +import org.eclipse.jdt.core.compiler.IProblem; +import org.eclipse.jdt.internal.compiler.parser.Scanner; +import org.eclipse.jdt.internal.compiler.util.Util; +import org.eclipse.jface.text.IDocument; +import org.eclipse.text.edits.TextEdit; + +/** + * Java compilation unit AST node type. This is the type of the root of an AST. + * <p> + * The source range for this type of node is ordinarily the entire source file, + * including leading and trailing whitespace and comments. + * </p> + * For JLS2: + * <pre> + * CompilationUnit: + * [ PackageDeclaration ] + * { ImportDeclaration } + * { TypeDeclaration | <b>;</b> } + * </pre> + * For JLS3, the kinds of type declarations + * grew to include enum and annotation type declarations: + * <pre> + * CompilationUnit: + * [ PackageDeclaration ] + * { ImportDeclaration } + * { TypeDeclaration | EnumDeclaration | AnnotationTypeDeclaration | <b>;</b> } + * </pre> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class CompilationUnit extends ASTNode { + + /** + * Canonical empty list of messages. + */ + private static final Message[] EMPTY_MESSAGES = new Message[0]; + + /** + * Canonical empty list of problems. + */ + private static final IProblem[] EMPTY_PROBLEMS = new IProblem[0]; + + /** + * The "imports" structural property of this node type. + * + * @since 3.0 + */ + public static final ChildListPropertyDescriptor IMPORTS_PROPERTY = + new ChildListPropertyDescriptor(CompilationUnit.class, "imports", ImportDeclaration.class, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "package" structural property of this node type. + * + * @since 3.0 + */ + public static final ChildPropertyDescriptor PACKAGE_PROPERTY = + new ChildPropertyDescriptor(CompilationUnit.class, "package", PackageDeclaration.class, OPTIONAL, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + * @since 3.0 + */ + private static final List PROPERTY_DESCRIPTORS; + + /** + * The "types" structural property of this node type. + * + * @since 3.0 + */ + public static final ChildListPropertyDescriptor TYPES_PROPERTY = + new ChildListPropertyDescriptor(CompilationUnit.class, "types", AbstractTypeDeclaration.class, CYCLE_RISK); //$NON-NLS-1$ + + static { + List properyList = new ArrayList(4); + createPropertyList(CompilationUnit.class, properyList); + addProperty(PACKAGE_PROPERTY, properyList); + addProperty(IMPORTS_PROPERTY, properyList); + addProperty(TYPES_PROPERTY, properyList); + PROPERTY_DESCRIPTORS = reapPropertyList(properyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The comment mapper, or <code>null</code> if none; + * initially <code>null</code>. + * @since 3.0 + */ + private DefaultCommentMapper commentMapper = null; + + /** + * The Java type root (an <code>org.eclipse.jdt.core.ICompilationUnit</code> or an <code>org.eclipse.jdt.core.IClassFile</code>) + * this compilation unit was created from, or <code>null</code> if it was not created from a Java type root. + */ + private ITypeRoot typeRoot = null; + + /** + * The list of import declarations in textual order order; + * initially none (elementType: <code>ImportDeclaration</code>). + */ + private ASTNode.NodeList imports = + new ASTNode.NodeList(IMPORTS_PROPERTY); + + /** + * Line end table. If <code>lineEndTable[i] == p</code> then the + * line number <code>i+1</code> ends at character position + * <code>p</code>. Except for the last line, the positions are that + * of the last character of the line delimiter. + * For example, the source string <code>A\nB\nC</code> has + * line end table {1, 3} (if \n is one character). + */ + private int[] lineEndTable = Util.EMPTY_INT_ARRAY; + + /** + * Messages reported by the compiler during parsing or name resolution. + */ + private Message[] messages; + + /** + * The comment list (element type: <code>Comment</code>, + * or <code>null</code> if none; initially <code>null</code>. + * @since 3.0 + */ + private List optionalCommentList = null; + + /** + * The comment table, or <code>null</code> if none; initially + * <code>null</code>. This array is the storage underlying + * the <code>optionalCommentList</code> ArrayList. + * @since 3.0 + */ + Comment[] optionalCommentTable = null; + + /** + * The package declaration, or <code>null</code> if none; initially + * <code>null</code>. + */ + private PackageDeclaration optionalPackageDeclaration = null; + + /** + * Problems reported by the compiler during parsing or name resolution. + */ + private IProblem[] problems = EMPTY_PROBLEMS; + + /** + * Internal data used to perform statements recovery. + */ + private Object statementsRecoveryData; + + /** + * The list of type declarations in textual order order; + * initially none (elementType: <code>AbstractTypeDeclaration</code>) + */ + private ASTNode.NodeList types = + new ASTNode.NodeList(TYPES_PROPERTY); + + /** + * Creates a new AST node for a compilation owned by the given AST. + * The compilation unit initially has no package declaration, no + * import declarations, and no type declarations. + * <p> + * N.B. This constructor is package-private; all subclasses must be + * declared in the same package; clients are unable to declare + * additional subclasses. + * </p> + * + * @param ast the AST that is to own this node + */ + CompilationUnit(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + acceptChild(visitor, getPackage()); + acceptChildren(visitor, this.imports); + acceptChildren(visitor, this.types); + } + visitor.endVisit(this); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + CompilationUnit result = new CompilationUnit(target); + // n.b do not copy line number table or messages + result.setSourceRange(getStartPosition(), getLength()); + result.setPackage( + (PackageDeclaration) ASTNode.copySubtree(target, getPackage())); + result.imports().addAll(ASTNode.copySubtrees(target, imports())); + result.types().addAll(ASTNode.copySubtrees(target, types())); + return result; + } + + + /** + * Returns the column number corresponding to the given source character + * position in the original source string. Column number are zero-based. + * Return <code>-1</code> if it is beyond the valid range or <code>-2</code> + * if the column number information is unknown. + * + * @param position a 0-based character position, possibly + * negative or out of range + * @return the 0-based column number, or <code>-1</code> if the character + * position does not correspond to a source line in the original + * source file or <code>-2</code> if column number information is unknown for this + * compilation unit + * @see ASTParser + * @since 3.2 + */ + public int getColumnNumber(final int position) { + if (this.lineEndTable == null) return -2; + final int line = getLineNumber(position); + if (line == -1) { + return -1; + } + if (line == 1) { + if (position >= getStartPosition() + getLength()) return -1; + return position; + } + // length is different from 0 + int length = this.lineEndTable.length; + // -1 to for one-based to zero-based conversion. + // -1, again, to get previous line. + final int previousLineOffset = this.lineEndTable[line - 2]; + // previousLineOffset + 1 is the first character of the current line + final int offsetForLine = previousLineOffset + 1; + final int currentLineEnd = line == length + 1 ? getStartPosition() + getLength() - 1 : this.lineEndTable[line - 1]; + if (offsetForLine > currentLineEnd) { + return -1; + } else { + return position - offsetForLine; + } + } + + /** + * Finds the corresponding AST node in the given compilation unit from + * which the given binding originated. Returns <code>null</code> if the + * binding does not correspond to any node in this compilation unit. + * This method always returns <code>null</code> if bindings were not requested + * when this AST was built. + * <p> + * The following table indicates the expected node type for the various + * different kinds of bindings: + * <ul> + * <li>package - a <code>PackageDeclaration</code></li> + * <li>class or interface - a <code>TypeDeclaration</code> or a + * <code>AnonymousClassDeclaration</code> (for anonymous classes)</li> + * <li>primitive type - none</li> + * <li>array type - none</li> + * <li>field - a <code>VariableDeclarationFragment</code> in a + * <code>FieldDeclaration</code> </li> + * <li>local variable - a <code>SingleVariableDeclaration</code>, or + * a <code>VariableDeclarationFragment</code> in a + * <code>VariableDeclarationStatement</code> or + * <code>VariableDeclarationExpression</code></li> + * <li>method - a <code>MethodDeclaration</code> </li> + * <li>constructor - a <code>MethodDeclaration</code> </li> + * <li>annotation type - an <code>AnnotationTypeDeclaration</code></li> + * <li>annotation type member - an <code>AnnotationTypeMemberDeclaration</code></li> + * <li>enum type - an <code>EnumDeclaration</code></li> + * <li>enum constant - an <code>EnumConstantDeclaration</code></li> + * <li>type variable - a <code>TypeParameter</code></li> + * <li>capture binding - none</li> + * <li>annotation binding - an <code>Annotation</code></li> + * <li>member value pair binding - an <code>MemberValuePair</code>, + * or <code>null</code> if it represents a default value or a single member value</li> + * </ul> + * For parameterized or raw type bindings, the declaring node is + * that of the corresponding generic type. And for parameterized or raw + * method bindings, the declaring node is that of the corresponding + * generic method. + * </p> + * <p> + * Each call to {@link ASTParser#createAST(org.eclipse.core.runtime.IProgressMonitor)} with a request for bindings + * gives rise to separate universe of binding objects. This method always returns + * <code>null</code> when the binding object comes from a different AST. + * Use <code>findDeclaringNode(binding.getKey())</code> when the binding comes + * from a different AST. + * </p> + * + * @param binding the binding + * @return the corresponding node where the given binding is declared, + * or <code>null</code> if the binding does not correspond to a node in this + * compilation unit or if bindings were not requested when this AST was built + * @see #findDeclaringNode(String) + */ + public ASTNode findDeclaringNode(IBinding binding) { + return this.ast.getBindingResolver().findDeclaringNode(binding); + } + + /** + * Finds the corresponding AST node in the given compilation unit from + * which the binding with the given key originated. Returns + * <code>null</code> if the corresponding node cannot be determined. + * This method always returns <code>null</code> if bindings were not requested + * when this AST was built. + * <p> + * The following table indicates the expected node type for the various + * different kinds of binding keys: + * <ul> + * <li></li> + * <li>package - a <code>PackageDeclaration</code></li> + * <li>class or interface - a <code>TypeDeclaration</code> or a + * <code>AnonymousClassDeclaration</code> (for anonymous classes)</li> + * <li>primitive type - none</li> + * <li>array type - none</li> + * <li>field - a <code>VariableDeclarationFragment</code> in a + * <code>FieldDeclaration</code> </li> + * <li>local variable - a <code>SingleVariableDeclaration</code>, or + * a <code>VariableDeclarationFragment</code> in a + * <code>VariableDeclarationStatement</code> or + * <code>VariableDeclarationExpression</code></li> + * <li>method - a <code>MethodDeclaration</code> </li> + * <li>constructor - a <code>MethodDeclaration</code> </li> + * <li>annotation type - an <code>AnnotationTypeDeclaration</code></li> + * <li>annotation type member - an <code>AnnotationTypeMemberDeclaration</code></li> + * <li>enum type - an <code>EnumDeclaration</code></li> + * <li>enum constant - an <code>EnumConstantDeclaration</code></li> + * <li>type variable - a <code>TypeParameter</code></li> + * <li>capture binding - none</li> + * </ul> + * For parameterized or raw type bindings, the declaring node is + * that of the corresponding generic type. And for parameterized or raw + * method bindings, the declaring node is that of the corresponding + * generic method. + * </p> + * + * @param key the binding key, or <code>null</code> + * @return the corresponding node where a binding with the given + * key is declared, or <code>null</code> if the key is <code>null</code> + * or if the key does not correspond to a node in this compilation unit + * or if bindings were not requested when this AST was built + * @see IBinding#getKey() + * @since 2.1 + */ + public ASTNode findDeclaringNode(String key) { + return this.ast.getBindingResolver().findDeclaringNode(key); + } + + /** + * Returns a list of the comments encountered while parsing + * this compilation unit. + * <p> + * Since the Java language allows comments to appear most anywhere + * in the source text, it is problematic to locate comments in relation + * to the structure of an AST. The one exception is doc comments + * which, by convention, immediately precede type, field, and + * method declarations; these comments are located in the AST + * by {@link BodyDeclaration#getJavadoc BodyDeclaration.getJavadoc}. + * Other comments do not show up in the AST. The table of comments + * is provided for clients that need to find the source ranges of + * all comments in the original source string. It includes entries + * for comments of all kinds (line, block, and doc), arranged in order + * of increasing source position. + * </p> + * <p> + * Note on comment parenting: The {@link ASTNode#getParent() getParent()} + * of a doc comment associated with a body declaration is the body + * declaration node; for these comment nodes + * {@link ASTNode#getRoot() getRoot()} will return the compilation unit + * (assuming an unmodified AST) reflecting the fact that these nodes + * are property located in the AST for the compilation unit. + * However, for other comment nodes, {@link ASTNode#getParent() getParent()} + * will return <code>null</code>, and {@link ASTNode#getRoot() getRoot()} + * will return the comment node itself, indicating that these comment nodes + * are not directly connected to the AST for the compilation unit. The + * {@link Comment#getAlternateRoot Comment.getAlternateRoot} + * method provides a way to navigate from a comment to its compilation + * unit. + * </p> + * <p> + * A note on visitors: The only comment nodes that will be visited when + * visiting a compilation unit are the doc comments parented by body + * declarations. To visit all comments in normal reading order, iterate + * over the comment table and call {@link ASTNode#accept(ASTVisitor) accept} + * on each element. + * </p> + * <p> + * Clients cannot modify the resulting list. + * </p> + * + * @return an unmodifiable list of comments in increasing order of source + * start position, or <code>null</code> if comment information + * for this compilation unit is not available + * @see ASTParser + * @since 3.0 + */ + public List getCommentList() { + return this.optionalCommentList; + } + + /** + * Returns the internal comment mapper. + * + * @return the comment mapper, or <code>null</code> if none. + * @since 3.0 + */ + DefaultCommentMapper getCommentMapper() { + return this.commentMapper; + } + + /** + * Returns the extended source length of the given node. Unlike + * {@link ASTNode#getStartPosition()} and {@link ASTNode#getLength()}, + * the extended source range may include comments and whitespace + * immediately before or after the normal source range for the node. + * + * @param node the node + * @return a (possibly 0) length, or <code>0</code> + * if no source position information is recorded for this node + * @see #getExtendedStartPosition(ASTNode) + * @since 3.0 + */ + public int getExtendedLength(ASTNode node) { + if (node == null) { + throw new IllegalArgumentException(); + } + if (this.commentMapper == null || node.getAST() != getAST()) { + // fall back: use best info available + return node.getLength(); + } else { + return this.commentMapper.getExtendedLength(node); + } + } + + /** + * Returns the extended start position of the given node. Unlike + * {@link ASTNode#getStartPosition()} and {@link ASTNode#getLength()}, + * the extended source range may include comments and whitespace + * immediately before or after the normal source range for the node. + * + * @param node the node + * @return the 0-based character index, or <code>-1</code> + * if no source position information is recorded for this node + * @see #getExtendedLength(ASTNode) + * @since 3.0 + */ + public int getExtendedStartPosition(ASTNode node) { + if (node == null) { + throw new IllegalArgumentException(); + } + if (this.commentMapper == null || node.getAST() != getAST()) { + // fall back: use best info available + return node.getStartPosition(); + } else { + return this.commentMapper.getExtendedStartPosition(node); + } + } + + /** + * The Java element (an <code>org.eclipse.jdt.core.ICompilationUnit</code> or an <code>org.eclipse.jdt.core.IClassFile</code>) + * this compilation unit was created from, or <code>null</code> if it was not created from a Java element. + * + * @return the Java element this compilation unit was created from, or <code>null</code> if none + * @since 3.1 + * @see #getTypeRoot() + */ + public IJavaElement getJavaElement() { + return this.typeRoot; + } + + /** + * Returns the list of messages reported by the compiler during the parsing + * or the type checking of this compilation unit. This list might be a subset of + * errors detected and reported by a Java compiler. + * <p> + * This list of messages is suitable for simple clients that do little + * more than log the messages or display them to the user. Clients that + * need further details should call <code>getProblems</code> to get + * compiler problem objects. + * </p> + * + * @return the list of messages, possibly empty + * @see #getProblems() + * @see ASTParser + */ + public Message[] getMessages() { + if (this.messages == null) { + int problemLength = this.problems.length; + if (problemLength == 0) { + this.messages = EMPTY_MESSAGES; + } else { + this.messages = new Message[problemLength]; + for (int i = 0; i < problemLength; i++) { + IProblem problem = this.problems[i]; + int start = problem.getSourceStart(); + int end = problem.getSourceEnd(); + this.messages[i] = new Message(problem.getMessage(), start, end - start + 1); + } + } + } + return this.messages; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return COMPILATION_UNIT; + } + + /** + * Returns the node for the package declaration of this compilation + * unit, or <code>null</code> if this compilation unit is in the + * default package. + * + * @return the package declaration node, or <code>null</code> if none + */ + public PackageDeclaration getPackage() { + return this.optionalPackageDeclaration; + } + + /** + * Given a line number and column number, returns the corresponding + * position in the original source string. + * Returns -2 if no line number information is available for this + * compilation unit. + * Returns the total size of the source string if <code>line</code> + * is greater than the actual number lines in the unit. + * Returns -1 if <code>column</code> is less than 0, + * or the position of the last character of the line if <code>column</code> + * is beyond the legal range, or the given line number is less than one. + * + * @param line the one-based line number + * @param column the zero-based column number + * @return the 0-based character position in the source string; + * <code>-2</code> if line/column number information is not known + * for this compilation unit or <code>-1</code> the inputs are not valid + * @since 3.2 + */ + public int getPosition(int line, int column) { + if (this.lineEndTable == null) return -2; + if (line < 1 || column < 0) return -1; + int length; + if ((length = this.lineEndTable.length) == 0) { + if (line != 1) return -1; + return column >= getStartPosition() + getLength() ? -1 : column; + } + if (line == 1) { + final int endOfLine = this.lineEndTable[0]; + return column > endOfLine ? -1 : column; + } else if( line > length + 1 ) { + // greater than the number of lines in the source string. + return -1; + } + // -1 to for one-based to zero-based conversion. + // -1, again, to get previous line. + final int previousLineOffset = this.lineEndTable[line - 2]; + // previousLineOffset + 1 is the first character of the current line + final int offsetForLine = previousLineOffset + 1; + final int currentLineEnd = line == length + 1 ? getStartPosition() + getLength() - 1 : this.lineEndTable[line-1]; + if ((offsetForLine + column) > currentLineEnd) { + return -1; + } else { + return offsetForLine + column; + } + } + + /** + * Returns the list of detailed problem reports noted by the compiler + * during the parsing or the type checking of this compilation unit. This + * list might be a subset of errors detected and reported by a Java + * compiler. + * <p> + * Simple clients that do little more than log the messages or display + * them to the user should probably call <code>getMessages</code> instead. + * </p> + * + * @return the list of detailed problem objects, possibly empty + * @see #getMessages() + * @see ASTParser + * @since 2.1 + */ + public IProblem[] getProblems() { + return this.problems; + } + + /** + * Internal method + * + * This method return internal data used to perform statements recovery. + * + * @return internal data used to perform statements recovery. + * + * @noreference This method is not intended to be referenced by clients. + * @since 3.5 + */ + public Object getStatementsRecoveryData() { + return this.statementsRecoveryData; + } + + /** + * The Java type root (a {@link org.eclipse.jdt.core.ICompilationUnit compilation unit} or a {@link org.eclipse.jdt.core.IClassFile class file}) + * this compilation unit was created from, or <code>null</code> if it was not created from a Java type root. + * + * @return the Java type root this compilation unit was created from, or <code>null</code> if none + * @since 3.3 + */ + public ITypeRoot getTypeRoot() { + return this.typeRoot; + } + + /** + * Returns the live list of nodes for the import declarations of this + * compilation unit, in order of appearance. + * + * @return the live list of import declaration nodes + * (elementType: <code>ImportDeclaration</code>) + */ + public List imports() { + return this.imports; + } + + /** + * Return the index in the whole comments list {@link #getCommentList() } + * of the first leading comments associated with the given node. + * + * @param node the node + * @return 0-based index of first leading comment or -1 if node has no associated + * comment before its start position. + * @since 3.2 + */ + public int firstLeadingCommentIndex(ASTNode node) { + if (node == null) { + throw new IllegalArgumentException(); + } + if (this.commentMapper == null || node.getAST() != getAST()) { + return -1; + } + return this.commentMapper.firstLeadingCommentIndex(node); + } + + /** + * Return the index in the whole comments list {@link #getCommentList() } + * of the last trailing comments associated with the given node. + * + * @param node the node + * @return 0-based index of last trailing comment or -1 if node has no + * associated comment after its end position. + * @since 3.2 + */ + public int lastTrailingCommentIndex(ASTNode node) { + if (node == null) { + throw new IllegalArgumentException(); + } + if (this.commentMapper == null || node.getAST() != getAST()) { + return -1; + } + return this.commentMapper.lastTrailingCommentIndex(node); + } + + /** + * Initializes the internal comment mapper with the given + * scanner. + * + * @param scanner the scanner + * @since 3.0 + */ + void initCommentMapper(Scanner scanner) { + this.commentMapper = new DefaultCommentMapper(this.optionalCommentTable); + this.commentMapper.initialize(this, scanner); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalGetChildListProperty(ChildListPropertyDescriptor property) { + if (property == IMPORTS_PROPERTY) { + return imports(); + } + if (property == TYPES_PROPERTY) { + return types(); + } + // allow default implementation to flag the error + return super.internalGetChildListProperty(property); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == PACKAGE_PROPERTY) { + if (get) { + return getPackage(); + } else { + setPackage((PackageDeclaration) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + * @since 3.0 + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /** + * Returns the line number corresponding to the given source character + * position in the original source string. The initial line of the + * compilation unit is numbered 1, and each line extends through the + * last character of the end-of-line delimiter. The very last line extends + * through the end of the source string and has no line delimiter. + * For example, the source string <code>class A\n{\n}</code> has 3 lines + * corresponding to inclusive character ranges [0,7], [8,9], and [10,10]. + * Returns 1 for a character position that does not correspond to any + * source line, or if no line number information is available for this + * compilation unit. + * + * @param position a 0-based character position, possibly + * negative or out of range + * @return the 1-based line number, or <code>1</code> if the character + * position does not correspond to a source line in the original + * source file or if line number information is not known for this + * compilation unit + * @deprecated Use getLineNumber(int) instead. Be careful to handle the negative values. + * @see ASTParser + * @see #getLineNumber(int) + */ + public int lineNumber(int position) { + int lineNumber = getLineNumber(position); + return lineNumber < 1 ? 1 : lineNumber; + } + + /** + * Returns the line number corresponding to the given source character + * position in the original source string. The initial line of the + * compilation unit is numbered 1, and each line extends through the + * last character of the end-of-line delimiter. The very last line extends + * through the end of the source string and has no line delimiter. + * For example, the source string <code>class A\n{\n}</code> has 3 lines + * corresponding to inclusive character ranges [0,7], [8,9], and [10,10]. + * Returns -1 for a character position that does not correspond to any + * source line, or -2 if no line number information is available for this + * compilation unit. + * + * @param position a 0-based character position, possibly + * negative or out of range + * @return the 1-based line number, or <code>-1</code> if the character + * position does not correspond to a source line in the original + * source file or <code>-2</code> if line number information is not known for this + * compilation unit + * @see ASTParser + * @since 3.2 + */ + public int getLineNumber(int position) { + if (this.lineEndTable == null) return -2; + int length; + if ((length = this.lineEndTable.length) == 0) { + if (position >= getStartPosition() + getLength()) { + return -1; + } + return 1; + } + int low = 0; + if (position < 0) { + // position illegal + return -1; + } + if (position <= this.lineEndTable[low]) { + // before the first line delimiter + return 1; + } + // assert position > lineEndTable[low+1] && low == 0 + int hi = length - 1; + if (position > this.lineEndTable[hi]) { + // position beyond the last line separator + if (position >= getStartPosition() + getLength()) { + // this is beyond the end of the source length + return -1; + } else { + return length + 1; + } + } + // assert lineEndTable[low] < position <= lineEndTable[hi] + // && low == 0 && hi == length - 1 && low < hi + + // binary search line end table + while (true) { + // invariant lineEndTable[low] < position <= lineEndTable[hi] + // && 0 <= low < hi <= length - 1 + // reducing measure hi - low + if (low + 1 == hi) { + // assert lineEndTable[low] < position <= lineEndTable[low+1] + // position is on line low+1 (line number is low+2) + return low + 2; + } + // assert hi - low >= 2, so average is truly in between + int mid = low + (hi - low) / 2; + // assert 0 <= low < mid < hi <= length - 1 + if (position <= this.lineEndTable[mid]) { + // assert lineEndTable[low] < position <= lineEndTable[mid] + // && 0 <= low < mid < hi <= length - 1 + hi = mid; + } else { + // position > lineEndTable[mid] + // assert lineEndTable[mid] < position <= lineEndTable[hi] + // && 0 <= low < mid < hi <= length - 1 + low = mid; + } + // in both cases, invariant reachieved with reduced measure + } + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + int size = BASE_NODE_SIZE + 8 * 4; + if (this.lineEndTable != null) { + size += HEADERS + 4 * this.lineEndTable.length; + } + if (this.optionalCommentTable != null) { + size += HEADERS + 4 * this.optionalCommentTable.length; + } + // ignore the space taken up by optionalCommentList + return size; + } + + /** + * Enables the recording of changes to this compilation + * unit and its descendents. The compilation unit must have + * been created by <code>ASTParser</code> and still be in + * its original state. Once recording is on, + * arbitrary changes to the subtree rooted at this compilation + * unit are recorded internally. Once the modification has + * been completed, call <code>rewrite</code> to get an object + * representing the corresponding edits to the original + * source code string. + * + * @exception IllegalArgumentException if this compilation unit is + * marked as unmodifiable, or if this compilation unit has already + * been tampered with, or recording has already been enabled + * @since 3.0 + */ + public void recordModifications() { + getAST().recordModifications(this); + } + + /** + * Converts all modifications recorded for this compilation + * unit into an object representing the corresponding text + * edits to the given document containing the original source + * code for this compilation unit. + * <p> + * The compilation unit must have been created by + * <code>ASTParser</code> from the source code string in the + * given document, and recording must have been turned + * on with a prior call to <code>recordModifications</code> + * while the AST was still in its original state. + * </p> + * <p> + * Calling this methods does not discard the modifications + * on record. Subsequence modifications made to the AST + * are added to the ones already on record. If this method + * is called again later, the resulting text edit object will + * accurately reflect the net cumulative affect of all those + * changes. + * </p> + * + * @param document original document containing source code + * for this compilation unit + * @param options the table of formatter options + * (key type: <code>String</code>; value type: <code>String</code>); + * or <code>null</code> to use the standard global options + * {@link org.eclipse.jdt.core.JavaCore#getOptions() JavaCore.getOptions()}. + * @return text edit object describing the changes to the + * document corresponding to the recorded AST modifications + * @exception IllegalArgumentException if the document passed is + * <code>null</code> or does not correspond to this AST + * @exception IllegalStateException if <code>recordModifications</code> + * was not called to enable recording + * @see #recordModifications() + * @since 3.0 + */ + public TextEdit rewrite(IDocument document, Map options) { + return getAST().rewrite(document, options); + } + + /** + * Sets the list of the comments encountered while parsing + * this compilation unit. + * + * @param commentTable a list of comments in increasing order + * of source start position, or <code>null</code> if comment + * information for this compilation unit is not available + * @exception IllegalArgumentException if the comment table is + * not in increasing order of source position + * @see #getCommentList() + * @see ASTParser + * @since 3.0 + */ + void setCommentTable(Comment[] commentTable) { + // double check table to ensure that all comments have + // source positions and are in strictly increasing order + if (commentTable == null) { + this.optionalCommentList = null; + this.optionalCommentTable = null; + } else { + int nextAvailablePosition = 0; + for (int i = 0; i < commentTable.length; i++) { + Comment comment = commentTable[i]; + if (comment == null) { + throw new IllegalArgumentException(); + } + int start = comment.getStartPosition(); + int length = comment.getLength(); + if (start < 0 || length < 0 || start < nextAvailablePosition) { + throw new IllegalArgumentException(); + } + nextAvailablePosition = comment.getStartPosition() + comment.getLength(); + } + this.optionalCommentTable = commentTable; + List commentList = Arrays.asList(commentTable); + // protect the list from further modification + this.optionalCommentList = Collections.unmodifiableList(commentList); + } + } + + /** + * Sets the Java type root (a {@link org.eclipse.jdt.core.ICompilationUnit compilation unit} or a {@link org.eclipse.jdt.core.IClassFile class file}) + * this compilation unit was created from, or <code>null</code> if it was not created from a Java type root. + * + * @param typeRoot the Java type root this compilation unit was created from + */ + void setTypeRoot(ITypeRoot typeRoot) { + this.typeRoot = typeRoot; + } + + /** + * Sets the line end table for this compilation unit. + * If <code>lineEndTable[i] == p</code> then line number <code>i+1</code> + * ends at character position <code>p</code>. Except for the last line, the + * positions are that of (the last character of) the line delimiter. + * For example, the source string <code>A\nB\nC</code> has + * line end table {1, 3, 4}. + * + * @param lineEndTable the line end table + */ + void setLineEndTable(int[] lineEndTable) { + if (lineEndTable == null) { + throw new NullPointerException(); + } + // alternate root is *not* considered a structural property + // but we protect them nevertheless + checkModifiable(); + this.lineEndTable = lineEndTable; + } + + /** + * Sets or clears the package declaration of this compilation unit + * node to the given package declaration node. + * + * @param pkgDecl the new package declaration node, or + * <code>null</code> if this compilation unit does not have a package + * declaration (that is in the default package) + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public void setPackage(PackageDeclaration pkgDecl) { + ASTNode oldChild = this.optionalPackageDeclaration; + preReplaceChild(oldChild, pkgDecl, PACKAGE_PROPERTY); + this.optionalPackageDeclaration = pkgDecl; + postReplaceChild(oldChild, pkgDecl, PACKAGE_PROPERTY); + } + + + /** + * Sets the array of problems reported by the compiler during the parsing or + * name resolution of this compilation unit. + * + * @param problems the list of problems + */ + void setProblems(IProblem[] problems) { + if (problems == null) { + throw new IllegalArgumentException(); + } + this.problems = problems; + } + + /** + * Internal method + * + * Sets internal data used to perform statements recovery. + * @param data + * + * @noreference This method is not intended to be referenced by clients. + * @since 3.5 + */ + void setStatementsRecoveryData(Object data) { + this.statementsRecoveryData = data; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + int size = memSize(); + if (this.optionalPackageDeclaration != null) { + size += getPackage().treeSize(); + } + size += this.imports.listSize(); + size += this.types.listSize(); + // include disconnected comments + if (this.optionalCommentList != null) { + for (int i = 0; i < this.optionalCommentList.size(); i++) { + Comment comment = (Comment) this.optionalCommentList.get(i); + if (comment != null && comment.getParent() == null) { + size += comment.treeSize(); + } + } + } + return size; + } + + /** + * Returns the live list of nodes for the top-level type declarations of this + * compilation unit, in order of appearance. + * <p> + * Note that in JLS3, the types may include both enum declarations + * and annotation type declarations introduced in J2SE 5. + * For JLS2, the elements are always <code>TypeDeclaration</code>. + * </p> + * + * @return the live list of top-level type declaration + * nodes (elementType: <code>AbstractTypeDeclaration</code>) + */ + public List types() { + return this.types; + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CompilationUnitResolver.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CompilationUnitResolver.java new file mode 100644 index 000000000..d269ab760 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CompilationUnitResolver.java @@ -0,0 +1,1032 @@ +/******************************************************************************* + * Copyright (c) 2000, 2009 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 + * $Id: CompilationUnitResolver.java 23404 2010-02-03 14:10:22Z stephan $ + * + * Contributors: + * IBM Corporation - initial API and implementation + * Fraunhofer FIRST - extended API and implementation + * Technical University Berlin - extended API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.jdt.core.ICompilationUnit; +import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.core.WorkingCopyOwner; +import org.eclipse.jdt.core.compiler.CategorizedProblem; +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.CompilationResult; +import org.eclipse.jdt.internal.compiler.Compiler; +import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies; +import org.eclipse.jdt.internal.compiler.ICompilerRequestor; +import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy; +import org.eclipse.jdt.internal.compiler.IProblemFactory; +import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; +import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; +import org.eclipse.jdt.internal.compiler.env.AccessRestriction; +import org.eclipse.jdt.internal.compiler.env.INameEnvironment; +import org.eclipse.jdt.internal.compiler.env.ISourceType; +import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; +import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding; +import org.eclipse.jdt.internal.compiler.lookup.Binding; +import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers; +import org.eclipse.jdt.internal.compiler.lookup.PackageBinding; +import org.eclipse.jdt.internal.compiler.parser.Parser; +import org.eclipse.jdt.internal.compiler.problem.AbortCompilation; +import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory; +import org.eclipse.jdt.internal.compiler.problem.ProblemReporter; +import org.eclipse.jdt.internal.compiler.util.HashtableOfObject; +import org.eclipse.jdt.internal.compiler.util.HashtableOfObjectToInt; +import org.eclipse.jdt.internal.compiler.util.Messages; +import org.eclipse.jdt.internal.core.BinaryMember; +import org.eclipse.jdt.internal.core.CancelableNameEnvironment; +import org.eclipse.jdt.internal.core.CancelableProblemFactory; +import org.eclipse.jdt.internal.core.JavaProject; +import org.eclipse.jdt.internal.core.NameLookup; +import org.eclipse.jdt.internal.core.SourceRefElement; +import org.eclipse.jdt.internal.core.SourceTypeElementInfo; +import org.eclipse.jdt.internal.core.util.BindingKeyResolver; +import org.eclipse.jdt.internal.core.util.CommentRecorderParser; +import org.eclipse.jdt.internal.core.util.DOMFinder; +import org.eclipse.objectteams.otdt.core.exceptions.InternalCompilerError; +import org.eclipse.objectteams.otdt.internal.core.compiler.control.Dependencies; +import org.eclipse.objectteams.otdt.internal.core.compiler.control.ITranslationStates; + +/** + * <h4>OTDT changes:</h4> + * <dl> + * <dt>What:<dd> setup and use Dependencies for calling into the compiler. + * </dl> + */ +class CompilationUnitResolver extends Compiler { + + /* A list of int */ + static class IntArrayList { + public int[] list = new int[5]; + public int length = 0; + public void add(int i) { + if (this.list.length == this.length) { + System.arraycopy(this.list, 0, this.list = new int[this.length*2], 0, this.length); + } + this.list[this.length++] = i; + } + } + + /* + * The sources that were requested. + * Map from file name (char[]) to ICompilationUnit. + */ + HashtableOfObject requestedSources; + + /* + * The binding keys that were requested. + * Map from file name (char[]) to BindingKey (or ArrayList if multiple keys in the same file). + */ + HashtableOfObject requestedKeys; + + DefaultBindingResolver.BindingTables bindingTables; + + boolean hasCompilationAborted; + + private IProgressMonitor monitor; + + /** + * Answer a new CompilationUnitVisitor using the given name environment and compiler options. + * The environment and options will be in effect for the lifetime of the compiler. + * When the compiler is run, compilation results are sent to the given requestor. + * + * @param environment org.eclipse.jdt.internal.compiler.api.env.INameEnvironment + * Environment used by the compiler in order to resolve type and package + * names. The name environment implements the actual connection of the compiler + * to the outside world (for example, in batch mode the name environment is performing + * pure file accesses, reuse previous build state or connection to repositories). + * Note: the name environment is responsible for implementing the actual classpath + * rules. + * + * @param policy org.eclipse.jdt.internal.compiler.api.problem.IErrorHandlingPolicy + * Configurable part for problem handling, allowing the compiler client to + * specify the rules for handling problems (stop on first error or accumulate + * them all) and at the same time perform some actions such as opening a dialog + * in UI when compiling interactively. + * @see org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies + * + * @param compilerOptions The compiler options to use for the resolution. + * + * @param requestor org.eclipse.jdt.internal.compiler.api.ICompilerRequestor + * Component which will receive and persist all compilation results and is intended + * to consume them as they are produced. Typically, in a batch compiler, it is + * responsible for writing out the actual .class files to the file system. + * @see org.eclipse.jdt.internal.compiler.CompilationResult + * + * @param problemFactory org.eclipse.jdt.internal.compiler.api.problem.IProblemFactory + * Factory used inside the compiler to create problem descriptors. It allows the + * compiler client to supply its own representation of compilation problems in + * order to avoid object conversions. Note that the factory is not supposed + * to accumulate the created problems, the compiler will gather them all and hand + * them back as part of the compilation unit result. + */ + public CompilationUnitResolver( + INameEnvironment environment, + IErrorHandlingPolicy policy, + CompilerOptions compilerOptions, + ICompilerRequestor requestor, + IProblemFactory problemFactory, + IProgressMonitor monitor) { + + super(environment, policy, compilerOptions, requestor, problemFactory); + this.hasCompilationAborted = false; + this.monitor =monitor; + } + + /* + * Add additional source types + */ + public void accept(ISourceType[] sourceTypes, PackageBinding packageBinding, AccessRestriction accessRestriction) { + // Need to reparse the entire source of the compilation unit so as to get source positions + // (case of processing a source that was not known by beginToCompile (e.g. when asking to createBinding)) + SourceTypeElementInfo sourceType = (SourceTypeElementInfo) sourceTypes[0]; + accept((org.eclipse.jdt.internal.compiler.env.ICompilationUnit) sourceType.getHandle().getCompilationUnit(), accessRestriction); + } + + public synchronized void accept(org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit, AccessRestriction accessRestriction) { + super.accept(sourceUnit, accessRestriction); + } + + /** + * Add the initial set of compilation units into the loop + * -> build compilation unit declarations, their bindings and record their results. + */ + protected void beginToCompile(org.eclipse.jdt.internal.compiler.env.ICompilationUnit[] sourceUnits, String[] bindingKeys) { + int sourceLength = sourceUnits.length; + int keyLength = bindingKeys.length; + int maxUnits = sourceLength + keyLength; + this.totalUnits = 0; + this.unitsToProcess = new CompilationUnitDeclaration[maxUnits]; + int index = 0; + + // walks the source units + this.requestedSources = new HashtableOfObject(); + for (int i = 0; i < sourceLength; i++) { + org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit = sourceUnits[i]; + CompilationUnitDeclaration parsedUnit; + CompilationResult unitResult = + new CompilationResult(sourceUnit, index++, maxUnits, this.options.maxProblemsPerUnit); + try { + if (this.options.verbose) { + this.out.println( + Messages.bind(Messages.compilation_request, + new String[] { + String.valueOf(index++ + 1), + String.valueOf(maxUnits), + new String(sourceUnit.getFileName()) + })); + } + // diet parsing for large collection of units + if (this.totalUnits < this.parseThreshold) { + parsedUnit = this.parser.parse(sourceUnit, unitResult); + } else { + parsedUnit = this.parser.dietParse(sourceUnit, unitResult); + } + // initial type binding creation + this.lookupEnvironment.buildTypeBindings(parsedUnit, null /*no access restriction*/); + addCompilationUnit(sourceUnit, parsedUnit); + this.requestedSources.put(unitResult.getFileName(), sourceUnit); + worked(1); + } finally { + sourceUnits[i] = null; // no longer hold onto the unit + } + } + + // walk the binding keys + this.requestedKeys = new HashtableOfObject(); + for (int i = 0; i < keyLength; i++) { + BindingKeyResolver resolver = new BindingKeyResolver(bindingKeys[i], this, this.lookupEnvironment); + resolver.parse(true/*pause after fully qualified name*/); + // If it doesn't have a type name, then it is either an array type, package or base type, which will definitely not have a compilation unit. + // Skipping it will speed up performance because the call will open jars. (theodora) + CompilationUnitDeclaration parsedUnit = resolver.hasTypeName() ? resolver.getCompilationUnitDeclaration() : null; + if (parsedUnit != null) { + char[] fileName = parsedUnit.compilationResult.getFileName(); + Object existing = this.requestedKeys.get(fileName); + if (existing == null) + this.requestedKeys.put(fileName, resolver); + else if (existing instanceof ArrayList) + ((ArrayList) existing).add(resolver); + else { + ArrayList list = new ArrayList(); + list.add(existing); + list.add(resolver); + this.requestedKeys.put(fileName, list); + } + + } else { + char[] key = resolver.hasTypeName() + ? resolver.getKey().toCharArray() // binary binding + : CharOperation.concatWith(resolver.compoundName(), '.'); // package binding or base type binding + this.requestedKeys.put(key, resolver); + } + worked(1); + } + + // binding resolution + this.lookupEnvironment.completeTypeBindings(); + } + + IBinding createBinding(String key) { + if (this.bindingTables == null) + throw new RuntimeException("Cannot be called outside ASTParser#createASTs(...)"); //$NON-NLS-1$ + BindingKeyResolver keyResolver = new BindingKeyResolver(key, this, this.lookupEnvironment); + Binding compilerBinding = keyResolver.getCompilerBinding(); + if (compilerBinding == null) return null; + DefaultBindingResolver resolver = new DefaultBindingResolver(this.lookupEnvironment, null/*no owner*/, this.bindingTables, false); + return resolver.getBinding(compilerBinding); + } + + public static CompilationUnit convert(CompilationUnitDeclaration compilationUnitDeclaration, char[] source, int apiLevel, Map options, boolean needToResolveBindings, WorkingCopyOwner owner, DefaultBindingResolver.BindingTables bindingTables, int flags, IProgressMonitor monitor) { + BindingResolver resolver = null; + AST ast = AST.newAST(apiLevel); + ast.setDefaultNodeFlag(ASTNode.ORIGINAL); + CompilationUnit compilationUnit = null; + ASTConverter converter = new ASTConverter(options, needToResolveBindings, monitor); + if (needToResolveBindings) { + resolver = new DefaultBindingResolver(compilationUnitDeclaration.scope, owner, bindingTables, (flags & ICompilationUnit.ENABLE_BINDINGS_RECOVERY) != 0); + ast.setFlag(flags | AST.RESOLVED_BINDINGS); + } else { + resolver = new BindingResolver(); + ast.setFlag(flags); + } + ast.setBindingResolver(resolver); + converter.setAST(ast); + compilationUnit = converter.convert(compilationUnitDeclaration, source); + compilationUnit.setLineEndTable(compilationUnitDeclaration.compilationResult.getLineSeparatorPositions()); + ast.setDefaultNodeFlag(0); + ast.setOriginalModificationCount(ast.modificationCount()); + return compilationUnit; + } + + protected static CompilerOptions getCompilerOptions(Map options, boolean statementsRecovery) { + CompilerOptions compilerOptions = new CompilerOptions(options); + compilerOptions.performMethodsFullRecovery = statementsRecovery; + compilerOptions.performStatementsRecovery = statementsRecovery; + compilerOptions.parseLiteralExpressionsAsConstants = false; + compilerOptions.storeAnnotations = true /*store annotations in the bindings*/; + return compilerOptions; + } + /* + * Low-level API performing the actual compilation + */ + protected static IErrorHandlingPolicy getHandlingPolicy() { + + // passes the initial set of files to the batch oracle (to avoid finding more than once the same units when case insensitive match) + return new IErrorHandlingPolicy() { + public boolean stopOnFirstError() { + return false; + } + public boolean proceedOnErrors() { + return false; // stop if there are some errors + } + }; + } + + /* + * Answer the component to which will be handed back compilation results from the compiler + */ + protected static ICompilerRequestor getRequestor() { + return new ICompilerRequestor() { + public void acceptResult(CompilationResult compilationResult) { + // do nothing + } + }; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.compiler.Compiler#initializeParser() + */ + public void initializeParser() { + this.parser = new CommentRecorderParser(this.problemReporter, false); + } + public void process(CompilationUnitDeclaration unit, int i) { + // don't resolve a second time the same unit (this would create the same binding twice) + char[] fileName = unit.compilationResult.getFileName(); + if (this.requestedKeys.get(fileName) == null && this.requestedSources.get(fileName) == null) + super.process(unit, i); + } + /* + * Compiler crash recovery in case of unexpected runtime exceptions + */ + protected void handleInternalException( + Throwable internalException, + CompilationUnitDeclaration unit, + CompilationResult result) { + super.handleInternalException(internalException, unit, result); + if (unit != null) { + removeUnresolvedBindings(unit); + } + } + + /* + * Compiler recovery in case of internal AbortCompilation event + */ + protected void handleInternalException( + AbortCompilation abortException, + CompilationUnitDeclaration unit) { + super.handleInternalException(abortException, unit); + if (unit != null) { + removeUnresolvedBindings(unit); + } + this.hasCompilationAborted = true; + } + + public static void parse(ICompilationUnit[] compilationUnits, ASTRequestor astRequestor, int apiLevel, Map options, int flags, IProgressMonitor monitor) { + try { + CompilerOptions compilerOptions = new CompilerOptions(options); + compilerOptions.ignoreMethodBodies = (flags & ICompilationUnit.IGNORE_METHOD_BODIES) != 0; + Parser parser = new CommentRecorderParser( + new ProblemReporter( + DefaultErrorHandlingPolicies.proceedWithAllProblems(), + compilerOptions, + new DefaultProblemFactory()), + false); + int unitLength = compilationUnits.length; + if (monitor != null) monitor.beginTask("", unitLength); //$NON-NLS-1$ + for (int i = 0; i < unitLength; i++) { + org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit = (org.eclipse.jdt.internal.compiler.env.ICompilationUnit) compilationUnits[i]; + CompilationResult compilationResult = new CompilationResult(sourceUnit, 0, 0, compilerOptions.maxProblemsPerUnit); + CompilationUnitDeclaration compilationUnitDeclaration = parser.dietParse(sourceUnit, compilationResult); + + if (compilationUnitDeclaration.ignoreMethodBodies) { + compilationUnitDeclaration.ignoreFurtherInvestigation = true; + // if initial diet parse did not work, no need to dig into method bodies. + continue; + } + + //fill the methods bodies in order for the code to be generated + //real parse of the method.... + org.eclipse.jdt.internal.compiler.ast.TypeDeclaration[] types = compilationUnitDeclaration.types; + if (types != null) { + for (int j = 0, typeLength = types.length; j < typeLength; j++) { + types[j].parseMethods(parser, compilationUnitDeclaration); + } + } + + // convert AST + CompilationUnit node = convert(compilationUnitDeclaration, parser.scanner.getSource(), apiLevel, options, false/*don't resolve binding*/, null/*no owner needed*/, null/*no binding table needed*/, flags /* flags */, monitor); + node.setTypeRoot(compilationUnits[i]); + + // accept AST + astRequestor.acceptAST(compilationUnits[i], node); + + if (monitor != null) monitor.worked(1); + } + } finally { + if (monitor != null) monitor.done(); + } + } + + public static CompilationUnitDeclaration parse( + org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit, + NodeSearcher nodeSearcher, + Map settings, + int flags) { + if (sourceUnit == null) { + throw new IllegalStateException(); + } + CompilerOptions compilerOptions = new CompilerOptions(settings); + boolean statementsRecovery = (flags & ICompilationUnit.ENABLE_STATEMENTS_RECOVERY) != 0; + compilerOptions.performMethodsFullRecovery = statementsRecovery; + compilerOptions.performStatementsRecovery = statementsRecovery; + compilerOptions.ignoreMethodBodies = (flags & ICompilationUnit.IGNORE_METHOD_BODIES) != 0; + Parser parser = new CommentRecorderParser( + new ProblemReporter( + DefaultErrorHandlingPolicies.proceedWithAllProblems(), + compilerOptions, + new DefaultProblemFactory()), + false); + CompilationResult compilationResult = new CompilationResult(sourceUnit, 0, 0, compilerOptions.maxProblemsPerUnit); + CompilationUnitDeclaration compilationUnitDeclaration = parser.dietParse(sourceUnit, compilationResult); + + if (compilationUnitDeclaration.ignoreMethodBodies) { + compilationUnitDeclaration.ignoreFurtherInvestigation = true; + // if initial diet parse did not work, no need to dig into method bodies. + return compilationUnitDeclaration; + } + + if (nodeSearcher != null) { + char[] source = parser.scanner.getSource(); + int searchPosition = nodeSearcher.position; + if (searchPosition < 0 || searchPosition > source.length) { + // the position is out of range. There is no need to search for a node. + return compilationUnitDeclaration; + } + + compilationUnitDeclaration.traverse(nodeSearcher, compilationUnitDeclaration.scope); + + org.eclipse.jdt.internal.compiler.ast.ASTNode node = nodeSearcher.found; + if (node == null) { + return compilationUnitDeclaration; + } + + org.eclipse.jdt.internal.compiler.ast.TypeDeclaration enclosingTypeDeclaration = nodeSearcher.enclosingType; + + if (node instanceof AbstractMethodDeclaration) { + ((AbstractMethodDeclaration)node).parseStatements(parser, compilationUnitDeclaration); + } else if (enclosingTypeDeclaration != null) { + if (node instanceof org.eclipse.jdt.internal.compiler.ast.Initializer) { + ((org.eclipse.jdt.internal.compiler.ast.Initializer) node).parseStatements(parser, enclosingTypeDeclaration, compilationUnitDeclaration); + } else if (node instanceof org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) { + ((org.eclipse.jdt.internal.compiler.ast.TypeDeclaration)node).parseMethods(parser, compilationUnitDeclaration); + } + } + } else { + //fill the methods bodies in order for the code to be generated + //real parse of the method.... + org.eclipse.jdt.internal.compiler.ast.TypeDeclaration[] types = compilationUnitDeclaration.types; + if (types != null) { + for (int j = 0, typeLength = types.length; j < typeLength; j++) { + types[j].parseMethods(parser, compilationUnitDeclaration); + } + } + } + return compilationUnitDeclaration; + } + + public static void resolve( + ICompilationUnit[] compilationUnits, + String[] bindingKeys, + ASTRequestor requestor, + int apiLevel, + Map options, + IJavaProject javaProject, + WorkingCopyOwner owner, + int flags, + IProgressMonitor monitor) { + + CancelableNameEnvironment environment = null; + CancelableProblemFactory problemFactory = null; + try { + if (monitor != null) { + int amountOfWork = (compilationUnits.length + bindingKeys.length) * 2; // 1 for beginToCompile, 1 for resolve + monitor.beginTask("", amountOfWork); //$NON-NLS-1$ + } + environment = new CancelableNameEnvironment(((JavaProject) javaProject), owner, monitor); + problemFactory = new CancelableProblemFactory(monitor); + CompilerOptions compilerOptions = getCompilerOptions(options, (flags & ICompilationUnit.ENABLE_STATEMENTS_RECOVERY) != 0); + compilerOptions.ignoreMethodBodies = (flags & ICompilationUnit.IGNORE_METHOD_BODIES) != 0; + CompilationUnitResolver resolver = + new CompilationUnitResolver( + environment, + getHandlingPolicy(), + compilerOptions, + getRequestor(), + problemFactory, + monitor); + resolver.resolve(compilationUnits, bindingKeys, requestor, apiLevel, options, owner, flags); + if (NameLookup.VERBOSE) { + System.out.println(Thread.currentThread() + " TIME SPENT in NameLoopkup#seekTypesInSourcePackage: " + environment.nameLookup.timeSpentInSeekTypesInSourcePackage + "ms"); //$NON-NLS-1$ //$NON-NLS-2$ + System.out.println(Thread.currentThread() + " TIME SPENT in NameLoopkup#seekTypesInBinaryPackage: " + environment.nameLookup.timeSpentInSeekTypesInBinaryPackage + "ms"); //$NON-NLS-1$ //$NON-NLS-2$ + } + } catch (JavaModelException e) { + // project doesn't exist -> simple parse without resolving + parse(compilationUnits, requestor, apiLevel, options, flags, monitor); + } finally { + if (monitor != null) monitor.done(); + if (environment != null) { + environment.monitor = null; // don't hold a reference to this external object + } + if (problemFactory != null) { + problemFactory.monitor = null; // don't hold a reference to this external object + } + } + } + public static CompilationUnitDeclaration resolve( + org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit, + IJavaProject javaProject, + NodeSearcher nodeSearcher, + Map options, + WorkingCopyOwner owner, + int flags, + IProgressMonitor monitor) throws JavaModelException { + + CompilationUnitDeclaration unit = null; + CancelableNameEnvironment environment = null; + CancelableProblemFactory problemFactory = null; + CompilationUnitResolver resolver = null; + try { + environment = new CancelableNameEnvironment(((JavaProject)javaProject), owner, monitor); + problemFactory = new CancelableProblemFactory(monitor); + CompilerOptions compilerOptions = getCompilerOptions(options, (flags & ICompilationUnit.ENABLE_STATEMENTS_RECOVERY) != 0); + boolean ignoreMethodBodies = (flags & ICompilationUnit.IGNORE_METHOD_BODIES) != 0; + compilerOptions.ignoreMethodBodies = ignoreMethodBodies; + resolver = + new CompilationUnitResolver( + environment, + getHandlingPolicy(), + compilerOptions, + getRequestor(), + problemFactory, + monitor); + boolean analyzeAndGenerateCode = !ignoreMethodBodies; + unit = + resolver.resolve( + null, // no existing compilation unit declaration + sourceUnit, + nodeSearcher, + true, // method verification + analyzeAndGenerateCode, // analyze code + analyzeAndGenerateCode); // generate code + if (resolver.hasCompilationAborted) { + // the bindings could not be resolved due to missing types in name environment + // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=86541 + CompilationUnitDeclaration unitDeclaration = parse(sourceUnit, nodeSearcher, options, flags); + final int problemCount = unit.compilationResult.problemCount; + if (problemCount != 0) { + unitDeclaration.compilationResult.problems = new CategorizedProblem[problemCount]; + System.arraycopy(unit.compilationResult.problems, 0, unitDeclaration.compilationResult.problems, 0, problemCount); + unitDeclaration.compilationResult.problemCount = problemCount; + } + return unitDeclaration; + } + if (NameLookup.VERBOSE) { + System.out.println(Thread.currentThread() + " TIME SPENT in NameLoopkup#seekTypesInSourcePackage: " + environment.nameLookup.timeSpentInSeekTypesInSourcePackage + "ms"); //$NON-NLS-1$ //$NON-NLS-2$ + System.out.println(Thread.currentThread() + " TIME SPENT in NameLoopkup#seekTypesInBinaryPackage: " + environment.nameLookup.timeSpentInSeekTypesInBinaryPackage + "ms"); //$NON-NLS-1$ //$NON-NLS-2$ + } + return unit; + } finally { + if (environment != null) { + environment.monitor = null; // don't hold a reference to this external object + } + if (problemFactory != null) { + problemFactory.monitor = null; // don't hold a reference to this external object + } + // first unit cleanup is done by caller, but cleanup all enqueued requested units (not processed) +// if (resolver != null) { +// for (int i = 1; i < resolver.totalUnits; i++) { // could be more requested units +// CompilationUnitDeclaration parsedUnit = resolver.unitsToProcess[i]; +// if (parsedUnit.scope != null) +// parsedUnit.scope.faultInTypes(); // force resolution of signatures, so clients can query DOM AST +// parsedUnit.cleanUp(); +// } +// } + } + } + public static IBinding[] resolve( + final IJavaElement[] elements, + int apiLevel, + Map compilerOptions, + IJavaProject javaProject, + WorkingCopyOwner owner, + int flags, + IProgressMonitor monitor) { + + final int length = elements.length; + final HashMap sourceElementPositions = new HashMap(); // a map from ICompilationUnit to int[] (positions in elements) + int cuNumber = 0; + final HashtableOfObjectToInt binaryElementPositions = new HashtableOfObjectToInt(); // a map from String (binding key) to int (position in elements) + for (int i = 0; i < length; i++) { + IJavaElement element = elements[i]; + if (!(element instanceof SourceRefElement)) + throw new IllegalStateException(element + " is not part of a compilation unit or class file"); //$NON-NLS-1$ + Object cu = element.getAncestor(IJavaElement.COMPILATION_UNIT); + if (cu != null) { + // source member + IntArrayList intList = (IntArrayList) sourceElementPositions.get(cu); + if (intList == null) { + sourceElementPositions.put(cu, intList = new IntArrayList()); + cuNumber++; + } + intList.add(i); + } else { + // binary member + try { + String key = ((BinaryMember) element).getKey(true/*open to get resolved info*/); + binaryElementPositions.put(key, i); + } catch (JavaModelException e) { + throw new IllegalArgumentException(element + " does not exist"); //$NON-NLS-1$ + } + } + } + ICompilationUnit[] cus = new ICompilationUnit[cuNumber]; + sourceElementPositions.keySet().toArray(cus); + + int bindingKeyNumber = binaryElementPositions.size(); + String[] bindingKeys = new String[bindingKeyNumber]; + binaryElementPositions.keysToArray(bindingKeys); + + class Requestor extends ASTRequestor { + IBinding[] bindings = new IBinding[length]; + public void acceptAST(ICompilationUnit source, CompilationUnit ast) { + // TODO (jerome) optimize to visit the AST only once + IntArrayList intList = (IntArrayList) sourceElementPositions.get(source); + for (int i = 0; i < intList.length; i++) { + final int index = intList.list[i]; + SourceRefElement element = (SourceRefElement) elements[index]; + DOMFinder finder = new DOMFinder(ast, element, true/*resolve binding*/); + try { + finder.search(); + } catch (JavaModelException e) { + throw new IllegalArgumentException(element + " does not exist"); //$NON-NLS-1$ + } + this.bindings[index] = finder.foundBinding; + } + } + public void acceptBinding(String bindingKey, IBinding binding) { + int index = binaryElementPositions.get(bindingKey); + this.bindings[index] = binding; + } + } + Requestor requestor = new Requestor(); + resolve(cus, bindingKeys, requestor, apiLevel, compilerOptions, javaProject, owner, flags, monitor); + return requestor.bindings; + } + /* + * When unit result is about to be accepted, removed back pointers + * to unresolved bindings + */ + public void removeUnresolvedBindings(CompilationUnitDeclaration compilationUnitDeclaration) { + final org.eclipse.jdt.internal.compiler.ast.TypeDeclaration[] types = compilationUnitDeclaration.types; + if (types != null) { + for (int i = 0, max = types.length; i < max; i++) { + removeUnresolvedBindings(types[i]); + } + } + } + private void removeUnresolvedBindings(org.eclipse.jdt.internal.compiler.ast.TypeDeclaration type) { + final org.eclipse.jdt.internal.compiler.ast.TypeDeclaration[] memberTypes = type.memberTypes; + if (memberTypes != null) { + for (int i = 0, max = memberTypes.length; i < max; i++){ + removeUnresolvedBindings(memberTypes[i]); + } + } + if (type.binding != null && (type.binding.modifiers & ExtraCompilerModifiers.AccUnresolved) != 0) { + type.binding = null; + } + + final org.eclipse.jdt.internal.compiler.ast.FieldDeclaration[] fields = type.fields; + if (fields != null) { + for (int i = 0, max = fields.length; i < max; i++){ + if (fields[i].binding != null && (fields[i].binding.modifiers & ExtraCompilerModifiers.AccUnresolved) != 0) { + fields[i].binding = null; + } + } + } + + final AbstractMethodDeclaration[] methods = type.methods; + if (methods != null) { + for (int i = 0, max = methods.length; i < max; i++){ + if (methods[i].binding != null && (methods[i].binding.modifiers & ExtraCompilerModifiers.AccUnresolved) != 0) { + methods[i].binding = null; + } + } + } + } + + private void resolve(ICompilationUnit[] compilationUnits, String[] bindingKeys, ASTRequestor astRequestor, int apiLevel, Map compilerOptions, WorkingCopyOwner owner, int flags) { + + // temporarily connect ourselves to the ASTResolver - must disconnect when done + astRequestor.compilationUnitResolver = this; + this.bindingTables = new DefaultBindingResolver.BindingTables(); + CompilationUnitDeclaration unit = null; + try { + int length = compilationUnits.length; + org.eclipse.jdt.internal.compiler.env.ICompilationUnit[] sourceUnits = new org.eclipse.jdt.internal.compiler.env.ICompilationUnit[length]; + System.arraycopy(compilationUnits, 0, sourceUnits, 0, length); +//{ObjectTeams: + Dependencies.setup(this, this.parser, this.lookupEnvironment, + true/*verify*/, !this.options.ignoreMethodBodies/*analyze*/, !this.options.ignoreMethodBodies/*generate*/, + true, true, false); +// SH+KM} + + beginToCompile(sourceUnits, bindingKeys); + // process all units (some more could be injected in the loop by the lookup environment) + for (int i = 0; i < this.totalUnits; i++) { + if (resolvedRequestedSourcesAndKeys(i)) { + // no need to keep resolving if no more ASTs and no more binding keys are needed + // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=114935 + // cleanup remaining units + for (; i < this.totalUnits; i++) { + this.unitsToProcess[i].cleanUp(); + this.unitsToProcess[i] = null; + } + break; + } + unit = this.unitsToProcess[i]; + try { + super.process(unit, i); // this.process(...) is optimized to not process already known units + + // requested AST + char[] fileName = unit.compilationResult.getFileName(); + ICompilationUnit source = (ICompilationUnit) this.requestedSources.get(fileName); + if (source != null) { + // convert AST + CompilationResult compilationResult = unit.compilationResult; + org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit = compilationResult.compilationUnit; + char[] contents = sourceUnit.getContents(); + AST ast = AST.newAST(apiLevel); + ast.setFlag(flags | AST.RESOLVED_BINDINGS); + ast.setDefaultNodeFlag(ASTNode.ORIGINAL); + ASTConverter converter = new ASTConverter(compilerOptions, true/*need to resolve bindings*/, this.monitor); + BindingResolver resolver = new DefaultBindingResolver(unit.scope, owner, this.bindingTables, (flags & ICompilationUnit.ENABLE_BINDINGS_RECOVERY) != 0); + ast.setBindingResolver(resolver); + converter.setAST(ast); + CompilationUnit compilationUnit = converter.convert(unit, contents); + compilationUnit.setTypeRoot(source); + compilationUnit.setLineEndTable(compilationResult.getLineSeparatorPositions()); + ast.setDefaultNodeFlag(0); + ast.setOriginalModificationCount(ast.modificationCount()); + + // pass it to requestor + astRequestor.acceptAST(source, compilationUnit); + + worked(1); + + // remove at the end so that we don't resolve twice if a source and a key for the same file name have been requested + this.requestedSources.put(fileName, null); // mark it as removed + } + + // requested binding + Object key = this.requestedKeys.get(fileName); + if (key != null) { + if (key instanceof BindingKeyResolver) { + reportBinding(key, astRequestor, owner, unit); + worked(1); + } else if (key instanceof ArrayList) { + Iterator iterator = ((ArrayList) key).iterator(); + while (iterator.hasNext()) { + reportBinding(iterator.next(), astRequestor, owner, unit); + worked(1); + } + } + + // remove at the end so that we don't resolve twice if a source and a key for the same file name have been requested + this.requestedKeys.put(fileName, null); // mark it as removed + } + } finally { + // cleanup compilation unit result + unit.cleanUp(); + } + this.unitsToProcess[i] = null; // release reference to processed unit declaration + this.requestor.acceptResult(unit.compilationResult.tagAsAccepted()); + } + + // remaining binding keys + DefaultBindingResolver resolver = new DefaultBindingResolver(this.lookupEnvironment, owner, this.bindingTables, (flags & ICompilationUnit.ENABLE_BINDINGS_RECOVERY) != 0); + Object[] keys = this.requestedKeys.valueTable; + for (int j = 0, keysLength = keys.length; j < keysLength; j++) { + BindingKeyResolver keyResolver = (BindingKeyResolver) keys[j]; + if (keyResolver == null) continue; + Binding compilerBinding = keyResolver.getCompilerBinding(); + IBinding binding = compilerBinding == null ? null : resolver.getBinding(compilerBinding); + // pass it to requestor + astRequestor.acceptBinding(((BindingKeyResolver) this.requestedKeys.valueTable[j]).getKey(), binding); + worked(1); + } + } catch (OperationCanceledException e) { + throw e; + } catch (AbortCompilation e) { + this.handleInternalException(e, unit); + } catch (Error e) { + this.handleInternalException(e, unit, null); + throw e; // rethrow + } catch (RuntimeException e) { + this.handleInternalException(e, unit, null); + throw e; // rethrow + } finally { + // disconnect ourselves from ast requestor + astRequestor.compilationUnitResolver = null; +//{ObjectTeams: restore: + Dependencies.release(this); +// SH+KM} + } + } + + private void reportBinding(Object key, ASTRequestor astRequestor, WorkingCopyOwner owner, CompilationUnitDeclaration unit) { + BindingKeyResolver keyResolver = (BindingKeyResolver) key; + Binding compilerBinding = keyResolver.getCompilerBinding(); + if (compilerBinding != null) { + DefaultBindingResolver resolver = new DefaultBindingResolver(unit.scope, owner, this.bindingTables, false); + AnnotationBinding annotationBinding = keyResolver.getAnnotationBinding(); + IBinding binding; + if (annotationBinding != null) { + binding = resolver.getAnnotationInstance(annotationBinding); + } else { + binding = resolver.getBinding(compilerBinding); + } + if (binding != null) + astRequestor.acceptBinding(keyResolver.getKey(), binding); + } + } + + private CompilationUnitDeclaration resolve( + CompilationUnitDeclaration unit, + org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit, + NodeSearcher nodeSearcher, + boolean verifyMethods, + boolean analyzeCode, + boolean generateCode) { + + try { + +//{ObjectTeams: + Dependencies.setup(this, this.parser, this.lookupEnvironment, + verifyMethods, analyzeCode, generateCode, true, true, false); +// SH} + if (unit == null) { + // build and record parsed units + this.parseThreshold = 0; // will request a full parse + beginToCompile(new org.eclipse.jdt.internal.compiler.env.ICompilationUnit[] { sourceUnit }); + // process all units (some more could be injected in the loop by the lookup environment) +//{ObjectTeams: due to role files the unit corresponding to sourceUnit need not be in position 0: +/* orig: + unit = this.unitsToProcess[0]; + :giro */ + unit = findCorrespondingUnit(this.unitsToProcess, sourceUnit); +// SH} + } else { + // initial type binding creation + this.lookupEnvironment.buildTypeBindings(unit, null /*no access restriction*/); + + // binding resolution + this.lookupEnvironment.completeTypeBindings(); + } + + if (nodeSearcher == null) { + this.parser.getMethodBodies(unit); // no-op if method bodies have already been parsed + } else { + int searchPosition = nodeSearcher.position; + char[] source = sourceUnit.getContents(); + int length = source.length; + if (searchPosition >= 0 && searchPosition <= length) { + unit.traverse(nodeSearcher, unit.scope); + + org.eclipse.jdt.internal.compiler.ast.ASTNode node = nodeSearcher.found; + + if (node != null) { + // save existing values to restore them at the end of the parsing process + // see bug 47079 for more details + int[] oldLineEnds = this.parser.scanner.lineEnds; + int oldLinePtr = this.parser.scanner.linePtr; + + this.parser.scanner.setSource(source, unit.compilationResult); + + org.eclipse.jdt.internal.compiler.ast.TypeDeclaration enclosingTypeDeclaration = nodeSearcher.enclosingType; + if (node instanceof AbstractMethodDeclaration) { + ((AbstractMethodDeclaration)node).parseStatements(this.parser, unit); + } else if (enclosingTypeDeclaration != null) { + if (node instanceof org.eclipse.jdt.internal.compiler.ast.Initializer) { + ((org.eclipse.jdt.internal.compiler.ast.Initializer) node).parseStatements(this.parser, enclosingTypeDeclaration, unit); + } else if (node instanceof org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) { + ((org.eclipse.jdt.internal.compiler.ast.TypeDeclaration)node).parseMethods(this.parser, unit); + } + } + // this is done to prevent any side effects on the compilation unit result + // line separator positions array. + this.parser.scanner.lineEnds = oldLineEnds; + this.parser.scanner.linePtr = oldLinePtr; + } +//{ObjectTeams: no more method bodies, have explicitly parsed those we need: + unit.parseMethodBodies = false; +// SH} + } + } + + if (unit.scope != null) { +//{ObjectTeams: replace single step by Dependencies: +/* orig: + // fault in fields & methods + unit.scope.faultInTypes(); + if (unit.scope != null && verifyMethods) { + // http://dev.eclipse.org/bugs/show_bug.cgi?id=23117 + // verify inherited methods + unit.scope.verifyMethods(this.lookupEnvironment.methodVerifier()); + } + // type checking + unit.resolve(); + + // flow analysis + if (analyzeCode) unit.analyseCode(); + + // code generation + if (generateCode) unit.generateCode(); +*/ + if (generateCode) + Dependencies.ensureState(unit, ITranslationStates.STATE_BYTE_CODE_GENERATED); + else if (analyzeCode) + Dependencies.ensureState(unit, ITranslationStates.STATE_CODE_ANALYZED); + else + Dependencies.ensureState(unit, ITranslationStates.STATE_RESOLVED); +// SH} + + // finalize problems (suppressWarnings) + unit.finalizeProblems(); + } + // TODO(SH): release also role file units! + if (this.unitsToProcess != null) this.unitsToProcess[0] = null; // release reference to processed unit declaration + this.requestor.acceptResult(unit.compilationResult.tagAsAccepted()); + return unit; + } catch (AbortCompilation e) { + this.handleInternalException(e, unit); + return unit == null ? this.unitsToProcess[0] : unit; + } catch (Error e) { + this.handleInternalException(e, unit, null); + throw e; // rethrow + } catch (RuntimeException e) { + this.handleInternalException(e, unit, null); + throw e; // rethrow + } finally { +//{ObjectTeams: + Dependencies.release(this); +// SH} + // No reset is performed there anymore since, + // within the CodeAssist (or related tools), + // the compiler may be called *after* a call + // to this resolve(...) method. And such a call + // needs to have a compiler with a non-empty + // environment. + // this.reset(); + } + } +//{ObjectTeams: helper for above: a parsed unit need not be the first in declarations, +// because a role file might have fetched its team. +// So search through the array! + private CompilationUnitDeclaration findCorrespondingUnit( + CompilationUnitDeclaration[] declarations, + org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit) + { + for(CompilationUnitDeclaration cud : declarations) { + if (CharOperation.equals(sourceUnit.getFileName(), cud.getFileName())) + return cud; + } + throw new InternalCompilerError("parsed unit not found in units: "+new String(sourceUnit.getFileName())); //$NON-NLS-1$ + } +// SH} + + /* + * Internal API used to resolve a given compilation unit. Can run a subset of the compilation process + */ + public CompilationUnitDeclaration resolve( + org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit, + boolean verifyMethods, + boolean analyzeCode, + boolean generateCode) { + + return resolve( + null, /* no existing compilation unit declaration*/ + sourceUnit, + null/*no node searcher*/, + verifyMethods, + analyzeCode, + generateCode); + } + + boolean resolvedRequestedSourcesAndKeys(int unitIndexToProcess) { + if (unitIndexToProcess < this.requestedSources.size() && unitIndexToProcess < this.requestedKeys.size()) + return false; // must process at least this many units before checking to see if all are done + + Object[] sources = this.requestedSources.valueTable; + for (int i = 0, l = sources.length; i < l; i++) + if (sources[i] != null) return false; + Object[] keys = this.requestedKeys.valueTable; + for (int i = 0, l = keys.length; i < l; i++) + if (keys[i] != null) return false; + return true; + } + + /* + * Internal API used to resolve a given compilation unit. Can run a subset of the compilation process + */ + public CompilationUnitDeclaration resolve( + CompilationUnitDeclaration unit, + org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit, + boolean verifyMethods, + boolean analyzeCode, + boolean generateCode) { + + return resolve( + unit, + sourceUnit, + null/*no node searcher*/, + verifyMethods, + analyzeCode, + generateCode); + } + + private void worked(int work) { + if (this.monitor != null) { + if (this.monitor.isCanceled()) + throw new OperationCanceledException(); + this.monitor.worked(work); + } + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ConditionalExpression.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ConditionalExpression.java new file mode 100644 index 000000000..633a985ac --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ConditionalExpression.java @@ -0,0 +1,334 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Conditional expression AST node type. + * + * <pre> + * ConditionalExpression: + * Expression <b>?</b> Expression <b>:</b> Expression + * </pre> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class ConditionalExpression extends Expression { + + /** + * The "expression" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor EXPRESSION_PROPERTY = + new ChildPropertyDescriptor(ConditionalExpression.class, "expression", Expression.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "thenExpression" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor THEN_EXPRESSION_PROPERTY = + new ChildPropertyDescriptor(ConditionalExpression.class, "thenExpression", Expression.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "elseExpression" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor ELSE_EXPRESSION_PROPERTY = + new ChildPropertyDescriptor(ConditionalExpression.class, "elseExpression", Expression.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List properyList = new ArrayList(4); + createPropertyList(ConditionalExpression.class, properyList); + addProperty(EXPRESSION_PROPERTY, properyList); + addProperty(THEN_EXPRESSION_PROPERTY, properyList); + addProperty(ELSE_EXPRESSION_PROPERTY, properyList); + PROPERTY_DESCRIPTORS = reapPropertyList(properyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The condition expression; lazily initialized; defaults to an unspecified, + * but legal, expression. + */ + private Expression conditionExpression = null; + + /** + * The "then" expression; lazily initialized; defaults to an unspecified, + * but legal, expression. + */ + private Expression thenExpression = null; + + /** + * The "else" expression; lazily initialized; defaults to an unspecified, + * but legal, expression. + */ + private Expression elseExpression = null; + + /** + * Creates a new unparented conditional expression node owned by the given + * AST. By default, the condition, "then", and "else" expresssions are + * unspecified, but legal. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + ConditionalExpression(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == EXPRESSION_PROPERTY) { + if (get) { + return getExpression(); + } else { + setExpression((Expression) child); + return null; + } + } + if (property == THEN_EXPRESSION_PROPERTY) { + if (get) { + return getThenExpression(); + } else { + setThenExpression((Expression) child); + return null; + } + } + if (property == ELSE_EXPRESSION_PROPERTY) { + if (get) { + return getElseExpression(); + } else { + setElseExpression((Expression) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return CONDITIONAL_EXPRESSION; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + ConditionalExpression result = new ConditionalExpression(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setExpression((Expression) getExpression().clone(target)); + result.setThenExpression( + (Expression) getThenExpression().clone(target)); + result.setElseExpression( + (Expression) getElseExpression().clone(target)); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + acceptChild(visitor, getExpression()); + acceptChild(visitor, getThenExpression()); + acceptChild(visitor, getElseExpression()); + } + visitor.endVisit(this); + } + + /** + * Returns the condition of this conditional expression. + * + * @return the condition node + */ + public Expression getExpression() { + if (this.conditionExpression == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.conditionExpression == null) { + preLazyInit(); + this.conditionExpression = new SimpleName(this.ast); + postLazyInit(this.conditionExpression, EXPRESSION_PROPERTY); + } + } + } + return this.conditionExpression; + } + + /** + * Sets the condition of this conditional expression. + * + * @param expression the condition node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setExpression(Expression expression) { + if (expression == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.conditionExpression; + preReplaceChild(oldChild, expression, EXPRESSION_PROPERTY); + this.conditionExpression = expression; + postReplaceChild(oldChild, expression, EXPRESSION_PROPERTY); + } + + /** + * Returns the "then" part of this conditional expression. + * + * @return the "then" expression node + */ + public Expression getThenExpression() { + if (this.thenExpression == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.thenExpression == null) { + preLazyInit(); + this.thenExpression = new SimpleName(this.ast); + postLazyInit(this.thenExpression, THEN_EXPRESSION_PROPERTY); + } + } + } + return this.thenExpression; + } + + /** + * Sets the "then" part of this conditional expression. + * + * @param expression the "then" expression node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setThenExpression(Expression expression) { + if (expression == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.thenExpression; + preReplaceChild(oldChild, expression, THEN_EXPRESSION_PROPERTY); + this.thenExpression = expression; + postReplaceChild(oldChild, expression, THEN_EXPRESSION_PROPERTY); + } + + /** + * Returns the "else" part of this conditional expression. + * + * @return the "else" expression node + */ + public Expression getElseExpression() { + if (this.elseExpression == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.elseExpression == null) { + preLazyInit(); + this.elseExpression = new SimpleName(this.ast); + postLazyInit(this.elseExpression, ELSE_EXPRESSION_PROPERTY); + } + } + } + return this.elseExpression; + } + + /** + * Sets the "else" part of this conditional expression. + * + * @param expression the "else" expression node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setElseExpression(Expression expression) { + if (expression == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.elseExpression; + preReplaceChild(oldChild, expression, ELSE_EXPRESSION_PROPERTY); + this.elseExpression = expression; + postReplaceChild(oldChild, expression, ELSE_EXPRESSION_PROPERTY); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + // treat Code as free + return BASE_NODE_SIZE + 3 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.conditionExpression == null ? 0 : getExpression().treeSize()) + + (this.thenExpression == null ? 0 : getThenExpression().treeSize()) + + (this.elseExpression == null ? 0 : getElseExpression().treeSize()); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ConstructorInvocation.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ConstructorInvocation.java new file mode 100644 index 000000000..69f5657ec --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ConstructorInvocation.java @@ -0,0 +1,252 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Alternate constructor invocation statement AST node type. + * For JLS2: + * <pre> + * ConstructorInvocation: + * <b>this</b> <b>(</b> [ Expression { <b>,</b> Expression } ] <b>)</b> <b>;</b> + * </pre> + * For JLS3, type arguments are added: + * <pre> + * ConstructorInvocation: + * [ <b><</b> Type { <b>,</b> Type } <b>></b> ] + * <b>this</b> <b>(</b> [ Expression { <b>,</b> Expression } ] <b>)</b> <b>;</b> + * </pre> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class ConstructorInvocation extends Statement { + + /** + * The "typeArguments" structural property of this node type (added in JLS3 API). + * @since 3.1 + */ + public static final ChildListPropertyDescriptor TYPE_ARGUMENTS_PROPERTY = + new ChildListPropertyDescriptor(ConstructorInvocation.class, "typeArguments", Type.class, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "arguments" structural property of this node type. + * @since 3.0 + */ + public static final ChildListPropertyDescriptor ARGUMENTS_PROPERTY = + new ChildListPropertyDescriptor(ConstructorInvocation.class, "arguments", Expression.class, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + * @since 3.0 + */ + private static final List PROPERTY_DESCRIPTORS_2_0; + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + * @since 3.1 + */ + private static final List PROPERTY_DESCRIPTORS_3_0; + + static { + List properyList = new ArrayList(2); + createPropertyList(ConstructorInvocation.class, properyList); + addProperty(ARGUMENTS_PROPERTY, properyList); + PROPERTY_DESCRIPTORS_2_0 = reapPropertyList(properyList); + + properyList = new ArrayList(3); + createPropertyList(ConstructorInvocation.class, properyList); + addProperty(TYPE_ARGUMENTS_PROPERTY, properyList); + addProperty(ARGUMENTS_PROPERTY, properyList); + PROPERTY_DESCRIPTORS_3_0 = reapPropertyList(properyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + if (apiLevel == AST.JLS2_INTERNAL) { + return PROPERTY_DESCRIPTORS_2_0; + } else { + return PROPERTY_DESCRIPTORS_3_0; + } + } + + /** + * The type arguments (element type: <code>Type</code>). + * Null in JLS2. Added in JLS3; defaults to an empty list + * (see constructor). + * @since 3.1 + */ + private ASTNode.NodeList typeArguments = null; + + /** + * The list of argument expressions (element type: + * <code>Expression</code>). Defaults to an empty list. + */ + private ASTNode.NodeList arguments = + new ASTNode.NodeList(ARGUMENTS_PROPERTY); + + /** + * Creates a new AST node for an alternate constructor invocation statement + * owned by the given AST. By default, an empty list of arguments. + * + * @param ast the AST that is to own this node + */ + ConstructorInvocation(AST ast) { + super(ast); + if (ast.apiLevel >= AST.JLS3) { + this.typeArguments = new ASTNode.NodeList(TYPE_ARGUMENTS_PROPERTY); + } + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalGetChildListProperty(ChildListPropertyDescriptor property) { + if (property == ARGUMENTS_PROPERTY) { + return arguments(); + } + if (property == TYPE_ARGUMENTS_PROPERTY) { + return typeArguments(); + } + // allow default implementation to flag the error + return super.internalGetChildListProperty(property); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return CONSTRUCTOR_INVOCATION; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + ConstructorInvocation result = new ConstructorInvocation(target); + result.setSourceRange(getStartPosition(), getLength()); + result.copyLeadingComment(this); + if (this.ast.apiLevel >= AST.JLS3) { + result.typeArguments().addAll(ASTNode.copySubtrees(target, typeArguments())); + } + result.arguments().addAll(ASTNode.copySubtrees(target, arguments())); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + if (this.ast.apiLevel >= AST.JLS3) { + acceptChildren(visitor, this.typeArguments); + } + acceptChildren(visitor, this.arguments); + } + visitor.endVisit(this); + } + + /** + * Returns the live ordered list of type arguments of this constructor + * invocation (added in JLS3 API). + * + * @return the live list of type arguments + * (element type: <code>Type</code>) + * @exception UnsupportedOperationException if this operation is used in + * a JLS2 AST + * @since 3.1 + */ + public List typeArguments() { + // more efficient than just calling unsupportedIn2() to check + if (this.typeArguments == null) { + unsupportedIn2(); + } + return this.typeArguments; + } + + /** + * Returns the live ordered list of argument expressions in this alternate + * constructor invocation statement. + * + * @return the live list of argument expressions + * (element type: <code>Expression</code>) + */ + public List arguments() { + return this.arguments; + } + + /** + * Resolves and returns the binding for the constructor invoked by this + * expression. + * <p> + * Note that bindings are generally unavailable unless requested when the + * AST is being built. + * </p> + * + * @return the constructor binding, or <code>null</code> if the binding + * cannot be resolved + */ + public IMethodBinding resolveConstructorBinding() { + return this.ast.getBindingResolver().resolveConstructor(this); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + // treat Code as free + return BASE_NODE_SIZE + 2 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.typeArguments == null ? 0 : this.typeArguments.listSize()) + + (this.arguments == null ? 0 : this.arguments.listSize()); + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ContinueStatement.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ContinueStatement.java new file mode 100644 index 000000000..48fde2419 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ContinueStatement.java @@ -0,0 +1,188 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Continue statement AST node type. + * + * <pre> + * ContinueStatement: + * <b>continue</b> [ Identifier ] <b>;</b> + * </pre> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class ContinueStatement extends Statement { + + /** + * The "label" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor LABEL_PROPERTY = + new ChildPropertyDescriptor(ContinueStatement.class, "label", SimpleName.class, OPTIONAL, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List properyList = new ArrayList(2); + createPropertyList(ContinueStatement.class, properyList); + addProperty(LABEL_PROPERTY, properyList); + PROPERTY_DESCRIPTORS = reapPropertyList(properyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The label, or <code>null</code> if none; none by default. + */ + private SimpleName optionalLabel = null; + + /** + * Creates a new unparented continue statement node owned by the given + * AST. By default, the continue statement has no label. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + ContinueStatement(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == LABEL_PROPERTY) { + if (get) { + return getLabel(); + } else { + setLabel((SimpleName) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return CONTINUE_STATEMENT; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + ContinueStatement result = new ContinueStatement(target); + result.setSourceRange(getStartPosition(), getLength()); + result.copyLeadingComment(this); + result.setLabel((SimpleName) ASTNode.copySubtree(target, getLabel())); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + acceptChild(visitor, getLabel()); + } + visitor.endVisit(this); + } + + /** + * Returns the label of this continue statement, or <code>null</code> if + * there is none. + * + * @return the label, or <code>null</code> if there is none + */ + public SimpleName getLabel() { + return this.optionalLabel; + } + + /** + * Sets or clears the label of this continue statement. + * + * @param label the label, or <code>null</code> if + * there is none + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public void setLabel(SimpleName label) { + ASTNode oldChild = this.optionalLabel; + preReplaceChild(oldChild, label, LABEL_PROPERTY); + this.optionalLabel = label; + postReplaceChild(oldChild, label, LABEL_PROPERTY); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return super.memSize() + 1 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.optionalLabel == null ? 0 : getLabel().treeSize()); + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultASTVisitor.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultASTVisitor.java new file mode 100644 index 000000000..d08c20151 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultASTVisitor.java @@ -0,0 +1,562 @@ +/******************************************************************************* + * Copyright (c) 2000, 2009 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.dom; +/** + */ +class DefaultASTVisitor extends ASTVisitor { + /** + * + */ + public DefaultASTVisitor() { + super(); + } + + /** + * + */ + public DefaultASTVisitor(boolean visitDocTags) { + super(visitDocTags); + } + + public void endVisit(AnnotationTypeDeclaration node) { + endVisitNode(node); + } + + public void endVisit(AnnotationTypeMemberDeclaration node) { + endVisitNode(node); + } + + public void endVisit(AnonymousClassDeclaration node) { + endVisitNode(node); + } + public void endVisit(ArrayAccess node) { + endVisitNode(node); + } + public void endVisit(ArrayCreation node) { + endVisitNode(node); + } + public void endVisit(ArrayInitializer node) { + endVisitNode(node); + } + public void endVisit(ArrayType node) { + endVisitNode(node); + } + public void endVisit(AssertStatement node) { + endVisitNode(node); + } + public void endVisit(Assignment node) { + endVisitNode(node); + } + public void endVisit(Block node) { + endVisitNode(node); + } + /* since 3.0 */ + public void endVisit(BlockComment node) { + endVisitNode(node); + } + public void endVisit(BooleanLiteral node) { + endVisitNode(node); + } + public void endVisit(BreakStatement node) { + endVisitNode(node); + } + public void endVisit(CastExpression node) { + endVisitNode(node); + } + public void endVisit(CatchClause node) { + endVisitNode(node); + } + public void endVisit(CharacterLiteral node) { + endVisitNode(node); + } + public void endVisit(ClassInstanceCreation node) { + endVisitNode(node); + } + public void endVisit(CompilationUnit node) { + endVisitNode(node); + } + public void endVisit(ConditionalExpression node) { + endVisitNode(node); + } + public void endVisit(ConstructorInvocation node) { + endVisitNode(node); + } + public void endVisit(ContinueStatement node) { + endVisitNode(node); + } + public void endVisit(DoStatement node) { + endVisitNode(node); + } + public void endVisit(EmptyStatement node) { + endVisitNode(node); + } + public void endVisit(EnhancedForStatement node) { + endVisitNode(node); + } + public void endVisit(EnumConstantDeclaration node) { + endVisitNode(node); + } + public void endVisit(EnumDeclaration node) { + endVisitNode(node); + } + public void endVisit(ExpressionStatement node) { + endVisitNode(node); + } + public void endVisit(FieldAccess node) { + endVisitNode(node); + } + public void endVisit(FieldDeclaration node) { + endVisitNode(node); + } + public void endVisit(ForStatement node) { + endVisitNode(node); + } + public void endVisit(IfStatement node) { + endVisitNode(node); + } + public void endVisit(ImportDeclaration node) { + endVisitNode(node); + } + public void endVisit(InfixExpression node) { + endVisitNode(node); + } + public void endVisit(Initializer node) { + endVisitNode(node); + } + public void endVisit(InstanceofExpression node) { + endVisitNode(node); + } + public void endVisit(Javadoc node) { + endVisitNode(node); + } + public void endVisit(LabeledStatement node) { + endVisitNode(node); + } + public void endVisit(LineComment node) { + endVisitNode(node); + } + public void endVisit(MarkerAnnotation node) { + endVisitNode(node); + } + public void endVisit(MemberRef node) { + endVisitNode(node); + } + public void endVisit(MemberValuePair node) { + endVisitNode(node); + } + public void endVisit(MethodDeclaration node) { + endVisitNode(node); + } + public void endVisit(MethodInvocation node) { + endVisitNode(node); + } + public void endVisit(MethodRef node) { + endVisitNode(node); + } + public void endVisit(MethodRefParameter node) { + endVisitNode(node); + } + public void endVisit(NormalAnnotation node) { + endVisitNode(node); + } + public void endVisit(NullLiteral node) { + endVisitNode(node); + } + public void endVisit(NumberLiteral node) { + endVisitNode(node); + } + public void endVisit(PackageDeclaration node) { + endVisitNode(node); + } + public void endVisit(ParameterizedType node) { + endVisitNode(node); + } + public void endVisit(ParenthesizedExpression node) { + endVisitNode(node); + } + public void endVisit(PostfixExpression node) { + endVisitNode(node); + } + public void endVisit(PrefixExpression node) { + endVisitNode(node); + } + public void endVisit(PrimitiveType node) { + endVisitNode(node); + } + public void endVisit(QualifiedName node) { + endVisitNode(node); + } + public void endVisit(QualifiedType node) { + endVisitNode(node); + } + public void endVisit(ReturnStatement node) { + endVisitNode(node); + } + public void endVisit(SimpleName node) { + endVisitNode(node); + } + public void endVisit(SimpleType node) { + endVisitNode(node); + } + public void endVisit(SingleMemberAnnotation node) { + endVisitNode(node); + } + public void endVisit(SingleVariableDeclaration node) { + endVisitNode(node); + } + public void endVisit(StringLiteral node) { + endVisitNode(node); + } + public void endVisit(SuperConstructorInvocation node) { + endVisitNode(node); + } + public void endVisit(SuperFieldAccess node) { + endVisitNode(node); + } + public void endVisit(SuperMethodInvocation node) { + endVisitNode(node); + } + + public void endVisit(SwitchCase node) { + endVisitNode(node); + } + public void endVisit(SwitchStatement node) { + endVisitNode(node); + } + public void endVisit(SynchronizedStatement node) { + endVisitNode(node); + } + public void endVisit(TagElement node) { + endVisitNode(node); + } + public void endVisit(TextElement node) { + endVisitNode(node); + } + public void endVisit(ThisExpression node) { + endVisitNode(node); + } + public void endVisit(ThrowStatement node) { + endVisitNode(node); + } + public void endVisit(TryStatement node) { + endVisitNode(node); + } + + public void endVisit(TypeDeclaration node) { + endVisitNode(node); + } + public void endVisit(TypeDeclarationStatement node) { + endVisitNode(node); + } + public void endVisit(TypeLiteral node) { + endVisitNode(node); + } + public void endVisit(TypeParameter node) { + endVisitNode(node); + } + public void endVisit(VariableDeclarationExpression node) { + endVisitNode(node); + } + public void endVisit(VariableDeclarationFragment node) { + endVisitNode(node); + } + public void endVisit(VariableDeclarationStatement node) { + endVisitNode(node); + } + public void endVisit(WhileStatement node) { + endVisitNode(node); + } + public void endVisit(WildcardType node) { + endVisitNode(node); + } + protected void endVisitNode(ASTNode node) { + // do nothing + } + public boolean visit(AnnotationTypeDeclaration node) { + return visitNode(node); + } + public boolean visit(AnnotationTypeMemberDeclaration node) { + return visitNode(node); + } + public boolean visit(AnonymousClassDeclaration node) { + return visitNode(node); + } + public boolean visit(ArrayAccess node) { + return visitNode(node); + } + public boolean visit(ArrayCreation node) { + return visitNode(node); + } + public boolean visit(ArrayInitializer node) { + return visitNode(node); + } + public boolean visit(ArrayType node) { + visitNode(node); + return false; + } + public boolean visit(AssertStatement node) { + return visitNode(node); + } + public boolean visit(Assignment node) { + return visitNode(node); + } + public boolean visit(Block node) { + return visitNode(node); + } + /* since 3.0 */ + public boolean visit(BlockComment node) { + return visitNode(node); + } + public boolean visit(BooleanLiteral node) { + return visitNode(node); + } + public boolean visit(BreakStatement node) { + return visitNode(node); + } + public boolean visit(CastExpression node) { + return visitNode(node); + } + public boolean visit(CatchClause node) { + return visitNode(node); + } + public boolean visit(CharacterLiteral node) { + return visitNode(node); + } + public boolean visit(ClassInstanceCreation node) { + return visitNode(node); + } + public boolean visit(CompilationUnit node) { + return visitNode(node); + } + public boolean visit(ConditionalExpression node) { + return visitNode(node); + } + public boolean visit(ConstructorInvocation node) { + return visitNode(node); + } + public boolean visit(ContinueStatement node) { + return visitNode(node); + } + public boolean visit(DoStatement node) { + return visitNode(node); + } + public boolean visit(EmptyStatement node) { + return visitNode(node); + } + public boolean visit(EnhancedForStatement node) { + return visitNode(node); + } + public boolean visit(EnumConstantDeclaration node) { + return visitNode(node); + } + public boolean visit(EnumDeclaration node) { + return visitNode(node); + } + public boolean visit(ExpressionStatement node) { + return visitNode(node); + } + public boolean visit(FieldAccess node) { + return visitNode(node); + } + public boolean visit(FieldDeclaration node) { + return visitNode(node); + } + public boolean visit(ForStatement node) { + return visitNode(node); + } + public boolean visit(IfStatement node) { + return visitNode(node); + } + public boolean visit(ImportDeclaration node) { + return visitNode(node); + } + public boolean visit(InfixExpression node) { + return visitNode(node); + } + public boolean visit(Initializer node) { + return visitNode(node); + } + public boolean visit(InstanceofExpression node) { + return visitNode(node); + } + public boolean visit(Javadoc node) { + // do not visit Javadoc tags by default. Use constructor with boolean to enable. + if (super.visit(node)) { + return visitNode(node); + } + return false; + } + public boolean visit(LabeledStatement node) { + return visitNode(node); + } + public boolean visit(LineComment node) { + return visitNode(node); + } + public boolean visit(MarkerAnnotation node) { + return visitNode(node); + } + public boolean visit(MemberRef node) { + return visitNode(node); + } + public boolean visit(MemberValuePair node) { + return visitNode(node); + } + public boolean visit(MethodDeclaration node) { + return visitNode(node); + } + public boolean visit(MethodInvocation node) { + return visitNode(node); + } + public boolean visit(MethodRef node) { + return visitNode(node); + } + public boolean visit(MethodRefParameter node) { + return visitNode(node); + } + public boolean visit(NormalAnnotation node) { + return visitNode(node); + } + public boolean visit(NullLiteral node) { + return visitNode(node); + } + public boolean visit(NumberLiteral node) { + return visitNode(node); + } + public boolean visit(PackageDeclaration node) { + return visitNode(node); + } + public boolean visit(ParameterizedType node) { + return visitNode(node); + } + public boolean visit(ParenthesizedExpression node) { + return visitNode(node); + } + public boolean visit(PostfixExpression node) { + return visitNode(node); + } + public boolean visit(PrefixExpression node) { + return visitNode(node); + } + + public boolean visit(PrimitiveType node) { + return visitNode(node); + } + public boolean visit(QualifiedName node) { + return visitNode(node); + } + public boolean visit(QualifiedType node) { + return visitNode(node); + } + public boolean visit(ReturnStatement node) { + return visitNode(node); + } + public boolean visit(SimpleName node) { + return visitNode(node); + } + public boolean visit(SimpleType node) { + return visitNode(node); + } + public boolean visit(SingleMemberAnnotation node) { + return visitNode(node); + } + public boolean visit(SingleVariableDeclaration node) { + return visitNode(node); + } + + public boolean visit(StringLiteral node) { + return visitNode(node); + } + + public boolean visit(SuperConstructorInvocation node) { + return visitNode(node); + } + + public boolean visit(SuperFieldAccess node) { + return visitNode(node); + } + + public boolean visit(SuperMethodInvocation node) { + return visitNode(node); + } + + public boolean visit(SwitchCase node) { + return visitNode(node); + } + + public boolean visit(SwitchStatement node) { + return visitNode(node); + } + + public boolean visit(SynchronizedStatement node) { + return visitNode(node); + } + + public boolean visit(TagElement node) { + return visitNode(node); + } + + public boolean visit(TextElement node) { + return visitNode(node); + } + + public boolean visit(ThisExpression node) { + return visitNode(node); + } + + public boolean visit(ThrowStatement node) { + return visitNode(node); + } + + public boolean visit(TryStatement node) { + return visitNode(node); + } + + public boolean visit(TypeDeclaration node) { + return visitNode(node); + } + + public boolean visit(TypeDeclarationStatement node) { + return visitNode(node); + } + + public boolean visit(TypeLiteral node) { + return visitNode(node); + } + + public boolean visit(TypeParameter node) { + return visitNode(node); + } + + public boolean visit(VariableDeclarationExpression node) { + return visitNode(node); + } + + public boolean visit(VariableDeclarationFragment node) { + return visitNode(node); + } + + public boolean visit(VariableDeclarationStatement node) { + return visitNode(node); + } + + public boolean visit(WhileStatement node) { + return visitNode(node); + } + + public boolean visit(WildcardType node) { + return visitNode(node); + } + + protected boolean visitNode(ASTNode node) { + return true; + } + +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultBindingResolver.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultBindingResolver.java new file mode 100644 index 000000000..1974eb14f --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultBindingResolver.java @@ -0,0 +1,2030 @@ +/******************************************************************************* + * Copyright (c) 2000, 2009 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 + * $Id: DefaultBindingResolver.java 23405 2010-02-03 17:02:18Z stephan $ + * + * Contributors: + * IBM Corporation - initial API and implementation + * Fraunhofer FIRST - extended API and implementation + * Technical University Berlin - extended API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.dom; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.jdt.core.WorkingCopyOwner; +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; +import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration; +import org.eclipse.jdt.internal.compiler.ast.AllocationExpression; +import org.eclipse.jdt.internal.compiler.ast.ArrayAllocationExpression; +import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; +import org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall; +import org.eclipse.jdt.internal.compiler.ast.FieldReference; +import org.eclipse.jdt.internal.compiler.ast.JavadocImplicitTypeReference; +import org.eclipse.jdt.internal.compiler.ast.ImportReference; +import org.eclipse.jdt.internal.compiler.ast.JavadocAllocationExpression; +import org.eclipse.jdt.internal.compiler.ast.JavadocFieldReference; +import org.eclipse.jdt.internal.compiler.ast.JavadocMessageSend; +import org.eclipse.jdt.internal.compiler.ast.JavadocQualifiedTypeReference; +import org.eclipse.jdt.internal.compiler.ast.JavadocSingleNameReference; +import org.eclipse.jdt.internal.compiler.ast.JavadocSingleTypeReference; +import org.eclipse.jdt.internal.compiler.ast.Literal; +import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; +import org.eclipse.jdt.internal.compiler.ast.MemberValuePair; +import org.eclipse.jdt.internal.compiler.ast.MessageSend; +import org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference; +import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference; +import org.eclipse.jdt.internal.compiler.ast.QualifiedSuperReference; +import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference; +import org.eclipse.jdt.internal.compiler.ast.SingleNameReference; +import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference; +import org.eclipse.jdt.internal.compiler.ast.ThisReference; +import org.eclipse.jdt.internal.compiler.ast.TypeReference; +import org.eclipse.jdt.internal.compiler.impl.Constant; +import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding; +import org.eclipse.jdt.internal.compiler.lookup.Binding; +import org.eclipse.jdt.internal.compiler.lookup.BlockScope; +import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope; +import org.eclipse.jdt.internal.compiler.lookup.ElementValuePair; +import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; +import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; +import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment; +import org.eclipse.jdt.internal.compiler.lookup.ParameterizedGenericMethodBinding; +import org.eclipse.jdt.internal.compiler.lookup.ProblemFieldBinding; +import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons; +import org.eclipse.jdt.internal.compiler.lookup.ProblemReferenceBinding; +import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; +import org.eclipse.jdt.internal.compiler.lookup.Scope; +import org.eclipse.jdt.internal.compiler.lookup.TagBits; +import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; +import org.eclipse.jdt.internal.compiler.lookup.TypeIds; +import org.eclipse.jdt.internal.compiler.problem.AbortCompilation; +import org.eclipse.jdt.internal.core.util.Util; +import org.eclipse.objectteams.otdt.internal.core.compiler.ast.AbstractMethodMappingDeclaration; +import org.eclipse.objectteams.otdt.internal.core.compiler.ast.BaseAllocationExpression; +import org.eclipse.objectteams.otdt.internal.core.compiler.ast.BaseCallMessageSend; +import org.eclipse.objectteams.otdt.internal.core.compiler.ast.FieldAccessSpec; +import org.eclipse.objectteams.otdt.internal.core.compiler.ast.LiftingTypeReference; +import org.eclipse.objectteams.otdt.internal.core.compiler.ast.MethodSpec; +import org.eclipse.objectteams.otdt.internal.core.compiler.ast.TSuperMessageSend; +import org.eclipse.objectteams.otdt.internal.core.compiler.control.Dependencies; +import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.CallinCalloutScope; + +/** + * Internal class for resolving bindings using old ASTs. + * <p> + * IMPORTANT: The methods on this class are synchronized. This is required + * because there may be multiple clients in separate threads concurrently + * reading an AST and asking for bindings for its nodes. These requests all + * end up invoking instance methods on this class. There are various internal + * tables and caches which are built and maintained in the course of looking + * up bindings. To ensure that they remain coherent in the presence of multiple + * threads, the methods are synchronized on the DefaultBindingResolver instance. + * </p> + */ +class DefaultBindingResolver extends BindingResolver { + + /* + * Holds on binding tables that can be shared by several ASTs. + */ + static class BindingTables { + + /** + * This map is used to get a binding from its binding key. + */ + Map bindingKeysToBindings; + /** + * This map is used to keep the correspondance between new bindings and the + * compiler bindings as well as new annotation instances to their internal counterpart. + * This is an identity map. We should only create one object for one binding or annotation. + */ + Map compilerBindingsToASTBindings; + + BindingTables() { + this.compilerBindingsToASTBindings = new HashMap(); + this.bindingKeysToBindings = new HashMap(); + } + + } + /** + * This map is used to retrieve the corresponding block scope for a ast node + */ + Map astNodesToBlockScope; + + /** + * This map is used to get an ast node from its binding (new binding) or DOM + */ + Map bindingsToAstNodes; + + /* + * The shared binding tables accros ASTs. + */ + BindingTables bindingTables; + + /** + * This map is used to retrieve an old ast node using the new ast node. This is not an + * identity map. + */ + Map newAstToOldAst; + + /** + * Compilation unit scope + */ + private CompilationUnitScope scope; + + /** + * The working copy owner that defines the context in which this resolver is creating the bindings. + */ + WorkingCopyOwner workingCopyOwner; + + /** + * Toggle controlling whether DOM bindings should be created when missing internal compiler bindings.. + */ + boolean isRecoveringBindings; + + /** + * Constructor for DefaultBindingResolver. + */ + DefaultBindingResolver(CompilationUnitScope scope, WorkingCopyOwner workingCopyOwner, BindingTables bindingTables, boolean isRecoveringBindings) { + this.newAstToOldAst = new HashMap(); + this.astNodesToBlockScope = new HashMap(); + this.bindingsToAstNodes = new HashMap(); + this.bindingTables = bindingTables; + this.scope = scope; + this.workingCopyOwner = workingCopyOwner; + this.isRecoveringBindings = isRecoveringBindings; + } + + DefaultBindingResolver(LookupEnvironment lookupEnvironment, WorkingCopyOwner workingCopyOwner, BindingTables bindingTables, boolean isRecoveringBindings) { + this.newAstToOldAst = new HashMap(); + this.astNodesToBlockScope = new HashMap(); + this.bindingsToAstNodes = new HashMap(); + this.bindingTables = bindingTables; + this.scope = new CompilationUnitScope(new CompilationUnitDeclaration(null, null, -1), lookupEnvironment); + this.workingCopyOwner = workingCopyOwner; + this.isRecoveringBindings = isRecoveringBindings; + } + + /* + * Method declared on BindingResolver. + */ + synchronized ASTNode findDeclaringNode(IBinding binding) { + if (binding == null) { + return null; + } + if (binding instanceof IMethodBinding) { + IMethodBinding methodBinding = (IMethodBinding) binding; +//{ObjectTeams: searching a role method could be answered by a callout defining this method: +/* orig: + return (ASTNode) this.bindingsToAstNodes.get(methodBinding.getMethodDeclaration()); + :giro */ + ASTNode result = (ASTNode) this.bindingsToAstNodes.get(methodBinding.getMethodDeclaration()); + if (result == null) { + // search the declaring role for callout bindings + ASTNode typeNode = findDeclaringNode(methodBinding.getDeclaringClass()); + if (typeNode instanceof RoleTypeDeclaration) { + RoleTypeDeclaration roleType = (RoleTypeDeclaration) typeNode; + for (Object bodyObj : roleType.bodyDeclarations()) { + if (bodyObj instanceof CalloutMappingDeclaration) { + // callout and method are considered "equal" + if (((CalloutMappingDeclaration) bodyObj).resolveBinding().isEqualTo(binding)) + return (ASTNode)bodyObj; + } + } + } + } + return result; +// SH} + } else if (binding instanceof ITypeBinding) { + ITypeBinding typeBinding = (ITypeBinding) binding; + return (ASTNode) this.bindingsToAstNodes.get(typeBinding.getTypeDeclaration()); + } else if (binding instanceof IVariableBinding) { + IVariableBinding variableBinding = (IVariableBinding) binding; + return (ASTNode) this.bindingsToAstNodes.get(variableBinding.getVariableDeclaration()); + } + return (ASTNode) this.bindingsToAstNodes.get(binding); + } + + synchronized ASTNode findDeclaringNode(String bindingKey) { + if (bindingKey == null) { + return null; + } + Object binding = this.bindingTables.bindingKeysToBindings.get(bindingKey); + if (binding == null) + return null; + return (ASTNode) this.bindingsToAstNodes.get(binding); + } + + IBinding getBinding(org.eclipse.jdt.internal.compiler.lookup.Binding binding) { + switch (binding.kind()) { + case Binding.PACKAGE: + return getPackageBinding((org.eclipse.jdt.internal.compiler.lookup.PackageBinding) binding); + case Binding.TYPE: + case Binding.BASE_TYPE: + case Binding.GENERIC_TYPE: + case Binding.PARAMETERIZED_TYPE: + case Binding.RAW_TYPE: + return getTypeBinding((org.eclipse.jdt.internal.compiler.lookup.TypeBinding) binding); + case Binding.ARRAY_TYPE: + case Binding.TYPE_PARAMETER: + return new TypeBinding(this, (org.eclipse.jdt.internal.compiler.lookup.TypeBinding) binding); + case Binding.METHOD: + return getMethodBinding((org.eclipse.jdt.internal.compiler.lookup.MethodBinding) binding); + case Binding.FIELD: + case Binding.LOCAL: + return getVariableBinding((org.eclipse.jdt.internal.compiler.lookup.VariableBinding) binding); + } + return null; + } + + Util.BindingsToNodesMap getBindingsToNodesMap() { + return new Util.BindingsToNodesMap() { + public org.eclipse.jdt.internal.compiler.ast.ASTNode get(Binding binding) { + return (org.eclipse.jdt.internal.compiler.ast.ASTNode) + DefaultBindingResolver.this.newAstToOldAst.get(DefaultBindingResolver.this.bindingsToAstNodes.get(binding)); + } + }; + } + + synchronized org.eclipse.jdt.internal.compiler.ast.ASTNode getCorrespondingNode(ASTNode currentNode) { + return (org.eclipse.jdt.internal.compiler.ast.ASTNode) this.newAstToOldAst.get(currentNode); + } + + /* + * Method declared on BindingResolver. + */ + synchronized IMethodBinding getMethodBinding(org.eclipse.jdt.internal.compiler.lookup.MethodBinding methodBinding) { + if (methodBinding != null && !methodBinding.isValidBinding()) { + org.eclipse.jdt.internal.compiler.lookup.ProblemMethodBinding problemMethodBinding = + (org.eclipse.jdt.internal.compiler.lookup.ProblemMethodBinding) methodBinding; + methodBinding = problemMethodBinding.closestMatch; + } + + if (methodBinding != null) { + if (!this.isRecoveringBindings && ((methodBinding.tagBits & TagBits.HasMissingType) != 0)) { + return null; + } + IMethodBinding binding = (IMethodBinding) this.bindingTables.compilerBindingsToASTBindings.get(methodBinding); + if (binding != null) { + return binding; + } + binding = new MethodBinding(this, methodBinding); + this.bindingTables.compilerBindingsToASTBindings.put(methodBinding, binding); + return binding; + } + return null; + } + + synchronized IMemberValuePairBinding getMemberValuePairBinding(ElementValuePair valuePair) { + if (valuePair == null || valuePair.binding == null) return null; + IMemberValuePairBinding binding = + (IMemberValuePairBinding) this.bindingTables.compilerBindingsToASTBindings.get(valuePair); + if (binding != null) + return binding; + binding = new MemberValuePairBinding(valuePair, this); + this.bindingTables.compilerBindingsToASTBindings.put(valuePair, binding); + return binding; + } + + /* + * Method declared on BindingResolver. + */ + synchronized IPackageBinding getPackageBinding(org.eclipse.jdt.internal.compiler.lookup.PackageBinding packageBinding) { + if (packageBinding == null) { + return null; + } + IPackageBinding binding = (IPackageBinding) this.bindingTables.compilerBindingsToASTBindings.get(packageBinding); + if (binding != null) { + return binding; + } + binding = new PackageBinding(packageBinding, this); + this.bindingTables.compilerBindingsToASTBindings.put(packageBinding, binding); + return binding; + } + private int getTypeArguments(ParameterizedQualifiedTypeReference typeReference) { + TypeReference[][] typeArguments = typeReference.typeArguments; + int value = 0; + for (int i = 0, max = typeArguments.length; i < max; i++) { + if ((typeArguments[i] != null) || (value != 0)) { + value++; + } + } + return value; + } + + /** + * Returns the new type binding corresponding to the given variable declaration. + * This is used for recovered binding only. + * <p> + * The default implementation of this method returns <code>null</code>. + * Subclasses may reimplement. + * </p> + * + * @param variableDeclaration the given variable declaration + * @return the new type binding + */ + synchronized ITypeBinding getTypeBinding(VariableDeclaration variableDeclaration) { + ITypeBinding binding = (ITypeBinding) this.bindingTables.compilerBindingsToASTBindings.get(variableDeclaration); + if (binding != null) { + return binding; + } + binding = new RecoveredTypeBinding(this, variableDeclaration); + this.bindingTables.compilerBindingsToASTBindings.put(variableDeclaration, binding); + return binding; + } + + /** + * Returns the new type binding corresponding to the given type. + * This is used for recovered binding only. + * <p> + * The default implementation of this method returns <code>null</code>. + * Subclasses may reimplement. + * </p> + * + * @param type the given type + * @return the new type binding + */ + synchronized ITypeBinding getTypeBinding(Type type) { + ITypeBinding binding = (ITypeBinding) this.bindingTables.compilerBindingsToASTBindings.get(type); + if (binding != null) { + return binding; + } + binding = new RecoveredTypeBinding(this, type); + this.bindingTables.compilerBindingsToASTBindings.put(type, binding); + return binding; + } + + /* + * Method declared on BindingResolver. + */ + synchronized ITypeBinding getTypeBinding(org.eclipse.jdt.internal.compiler.lookup.TypeBinding referenceBinding) { + if (referenceBinding == null) { + return null; + } else if (!referenceBinding.isValidBinding()) { + switch(referenceBinding.problemId()) { + case ProblemReasons.NotVisible : + case ProblemReasons.NonStaticReferenceInStaticContext : + if (referenceBinding instanceof ProblemReferenceBinding) { + ProblemReferenceBinding problemReferenceBinding = (ProblemReferenceBinding) referenceBinding; + org.eclipse.jdt.internal.compiler.lookup.TypeBinding binding2 = problemReferenceBinding.closestMatch(); + ITypeBinding binding = (ITypeBinding) this.bindingTables.compilerBindingsToASTBindings.get(binding2); + if (binding != null) { + return binding; + } + binding = new TypeBinding(this, binding2); + this.bindingTables.compilerBindingsToASTBindings.put(binding2, binding); + return binding; + } + break; + case ProblemReasons.NotFound : + if (!this.isRecoveringBindings) { + return null; + } + ITypeBinding binding = (ITypeBinding) this.bindingTables.compilerBindingsToASTBindings.get(referenceBinding); + if (binding != null) { + return binding; + } + if ((referenceBinding.tagBits & TagBits.HasMissingType) != 0) { + binding = new TypeBinding(this, referenceBinding); + } else { + binding = new RecoveredTypeBinding(this, referenceBinding); + } + this.bindingTables.compilerBindingsToASTBindings.put(referenceBinding, binding); + return binding; + } + return null; + } else { + if ((referenceBinding.tagBits & TagBits.HasMissingType) != 0 && !this.isRecoveringBindings) { + return null; + } + ITypeBinding binding = (ITypeBinding) this.bindingTables.compilerBindingsToASTBindings.get(referenceBinding); + if (binding != null) { + return binding; + } + binding = new TypeBinding(this, referenceBinding); + this.bindingTables.compilerBindingsToASTBindings.put(referenceBinding, binding); + return binding; + } + } + + /* + * Method declared on BindingResolver. + */ + synchronized ITypeBinding getTypeBinding(RecoveredTypeBinding recoveredTypeBinding, int dimensions) { + if (recoveredTypeBinding== null) { + return null; + } + return new RecoveredTypeBinding(this, recoveredTypeBinding, dimensions); + } + + synchronized IVariableBinding getVariableBinding(org.eclipse.jdt.internal.compiler.lookup.VariableBinding variableBinding, VariableDeclaration variableDeclaration) { + if (this.isRecoveringBindings) { + if (variableBinding != null) { + if (variableBinding.isValidBinding()) { + IVariableBinding binding = (IVariableBinding) this.bindingTables.compilerBindingsToASTBindings.get(variableBinding); + if (binding != null) { + return binding; + } + if (variableBinding.type != null) { + binding = new VariableBinding(this, variableBinding); + } else { + binding = new RecoveredVariableBinding(this, variableDeclaration); + } + this.bindingTables.compilerBindingsToASTBindings.put(variableBinding, binding); + return binding; + } else { + /* + * http://dev.eclipse.org/bugs/show_bug.cgi?id=24449 + */ + if (variableBinding instanceof ProblemFieldBinding) { + ProblemFieldBinding problemFieldBinding = (ProblemFieldBinding) variableBinding; + switch(problemFieldBinding.problemId()) { + case ProblemReasons.NotVisible : + case ProblemReasons.NonStaticReferenceInStaticContext : + case ProblemReasons.NonStaticReferenceInConstructorInvocation : + ReferenceBinding declaringClass = problemFieldBinding.declaringClass; + FieldBinding exactBinding = declaringClass.getField(problemFieldBinding.name, true /*resolve*/); + if (exactBinding != null) { + IVariableBinding variableBinding2 = (IVariableBinding) this.bindingTables.compilerBindingsToASTBindings.get(exactBinding); + if (variableBinding2 != null) { + return variableBinding2; + } + variableBinding2 = new VariableBinding(this, exactBinding); + this.bindingTables.compilerBindingsToASTBindings.put(exactBinding, variableBinding2); + return variableBinding2; + } + break; + } + } + } + } + return null; + } + return this.getVariableBinding(variableBinding); + } + + public WorkingCopyOwner getWorkingCopyOwner() { + return this.workingCopyOwner; + } + + /* + * Method declared on BindingResolver. + */ + synchronized IVariableBinding getVariableBinding(org.eclipse.jdt.internal.compiler.lookup.VariableBinding variableBinding) { + if (variableBinding != null) { + if (variableBinding.isValidBinding()) { + org.eclipse.jdt.internal.compiler.lookup.TypeBinding variableType = variableBinding.type; + if (variableType != null) { + if (!this.isRecoveringBindings && ((variableType.tagBits & TagBits.HasMissingType) != 0)) { + return null; + } + IVariableBinding binding = (IVariableBinding) this.bindingTables.compilerBindingsToASTBindings.get(variableBinding); + if (binding != null) { + return binding; + } + binding = new VariableBinding(this, variableBinding); + this.bindingTables.compilerBindingsToASTBindings.put(variableBinding, binding); + return binding; + } + } else { + /* + * http://dev.eclipse.org/bugs/show_bug.cgi?id=24449 + */ + if (variableBinding instanceof ProblemFieldBinding) { + ProblemFieldBinding problemFieldBinding = (ProblemFieldBinding) variableBinding; + switch(problemFieldBinding.problemId()) { + case ProblemReasons.NotVisible : + case ProblemReasons.NonStaticReferenceInStaticContext : + case ProblemReasons.NonStaticReferenceInConstructorInvocation : + ReferenceBinding declaringClass = problemFieldBinding.declaringClass; + FieldBinding exactBinding = declaringClass.getField(problemFieldBinding.name, true /*resolve*/); + if (exactBinding != null) { + IVariableBinding variableBinding2 = (IVariableBinding) this.bindingTables.compilerBindingsToASTBindings.get(exactBinding); + if (variableBinding2 != null) { + return variableBinding2; + } + variableBinding2 = new VariableBinding(this, exactBinding); + this.bindingTables.compilerBindingsToASTBindings.put(exactBinding, variableBinding2); + return variableBinding2; + } + break; + } + } + } + } + return null; + } + + synchronized IAnnotationBinding getAnnotationInstance(org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding internalInstance) { + if (internalInstance == null) return null; + ReferenceBinding annotationType = internalInstance.getAnnotationType(); + if (!this.isRecoveringBindings) { + if (annotationType == null || ((annotationType.tagBits & TagBits.HasMissingType) != 0)) { + return null; + } + } + IAnnotationBinding domInstance = + (IAnnotationBinding) this.bindingTables.compilerBindingsToASTBindings.get(internalInstance); + if (domInstance != null) + return domInstance; + domInstance = new AnnotationBinding(internalInstance, this); + this.bindingTables.compilerBindingsToASTBindings.put(internalInstance, domInstance); + return domInstance; + } + + boolean isResolvedTypeInferredFromExpectedType(MethodInvocation methodInvocation) { + Object oldNode = this.newAstToOldAst.get(methodInvocation); + if (oldNode instanceof MessageSend) { + MessageSend messageSend = (MessageSend) oldNode; + org.eclipse.jdt.internal.compiler.lookup.MethodBinding methodBinding = messageSend.binding; + if (methodBinding instanceof ParameterizedGenericMethodBinding) { + ParameterizedGenericMethodBinding genericMethodBinding = (ParameterizedGenericMethodBinding) methodBinding; + return genericMethodBinding.inferredReturnType; + } + } + return false; + } + + boolean isResolvedTypeInferredFromExpectedType(SuperMethodInvocation superMethodInvocation) { + Object oldNode = this.newAstToOldAst.get(superMethodInvocation); + if (oldNode instanceof MessageSend) { + MessageSend messageSend = (MessageSend) oldNode; + org.eclipse.jdt.internal.compiler.lookup.MethodBinding methodBinding = messageSend.binding; + if (methodBinding instanceof ParameterizedGenericMethodBinding) { + ParameterizedGenericMethodBinding genericMethodBinding = (ParameterizedGenericMethodBinding) methodBinding; + return genericMethodBinding.inferredReturnType; + } + } + return false; + } + + /* + * Method declared on BindingResolver. + */ + LookupEnvironment lookupEnvironment() { + return this.scope.environment(); + } + + /** + * @see org.eclipse.jdt.core.dom.BindingResolver#recordScope(ASTNode, BlockScope) + */ + synchronized void recordScope(ASTNode astNode, BlockScope blockScope) { + this.astNodesToBlockScope.put(astNode, blockScope); + } + + /* + * @see BindingResolver#resolveBoxing(Expression) + */ + boolean resolveBoxing(Expression expression) { + org.eclipse.jdt.internal.compiler.ast.ASTNode node = (org.eclipse.jdt.internal.compiler.ast.ASTNode) this.newAstToOldAst.get(expression); + if (node instanceof org.eclipse.jdt.internal.compiler.ast.Expression) { + org.eclipse.jdt.internal.compiler.ast.Expression compilerExpression = (org.eclipse.jdt.internal.compiler.ast.Expression) node; + return (compilerExpression.implicitConversion & TypeIds.BOXING) != 0; + } + return false; + } + + /* + * @see BindingResolver#resolveUnboxing(Expression) + */ + boolean resolveUnboxing(Expression expression) { + org.eclipse.jdt.internal.compiler.ast.ASTNode node = (org.eclipse.jdt.internal.compiler.ast.ASTNode) this.newAstToOldAst.get(expression); + if (node instanceof org.eclipse.jdt.internal.compiler.ast.Expression) { + org.eclipse.jdt.internal.compiler.ast.Expression compilerExpression = (org.eclipse.jdt.internal.compiler.ast.Expression) node; + return (compilerExpression.implicitConversion & TypeIds.UNBOXING) != 0; + } + return false; + } + + /* + * @see BindingResolver#resolveConstantExpressionValue(Expression) + */ + Object resolveConstantExpressionValue(Expression expression) { + org.eclipse.jdt.internal.compiler.ast.ASTNode node = (org.eclipse.jdt.internal.compiler.ast.ASTNode) this.newAstToOldAst.get(expression); + if (node instanceof org.eclipse.jdt.internal.compiler.ast.Expression) { + org.eclipse.jdt.internal.compiler.ast.Expression compilerExpression = (org.eclipse.jdt.internal.compiler.ast.Expression) node; + Constant constant = compilerExpression.constant; + if (constant != null && constant != Constant.NotAConstant) { + switch (constant.typeID()) { + case TypeIds.T_int : return new Integer(constant.intValue()); + case TypeIds.T_byte : return new Byte(constant.byteValue()); + case TypeIds.T_short : return new Short(constant.shortValue()); + case TypeIds.T_char : return new Character(constant.charValue()); + case TypeIds.T_float : return new Float(constant.floatValue()); + case TypeIds.T_double : return new Double(constant.doubleValue()); + case TypeIds.T_boolean : return constant.booleanValue() ? Boolean.TRUE : Boolean.FALSE; + case TypeIds.T_long : return new Long(constant.longValue()); + case TypeIds.T_JavaLangString : return constant.stringValue(); + } + return null; + } + } + return null; + } + + /* + * @see BindingResolver#resolveConstructor(ClassInstanceCreation) + */ + synchronized IMethodBinding resolveConstructor(ClassInstanceCreation expression) { + org.eclipse.jdt.internal.compiler.ast.ASTNode node = (org.eclipse.jdt.internal.compiler.ast.ASTNode) this.newAstToOldAst.get(expression); + if (node != null && (node.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.IsAnonymousType) != 0) { + org.eclipse.jdt.internal.compiler.ast.TypeDeclaration anonymousLocalTypeDeclaration = (org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) node; + return getMethodBinding(anonymousLocalTypeDeclaration.allocation.binding); + } else if (node instanceof AllocationExpression) { + return getMethodBinding(((AllocationExpression)node).binding); + } + return null; + } + + /* + * @see BindingResolver#resolveConstructor(ConstructorInvocation) + */ + synchronized IMethodBinding resolveConstructor(ConstructorInvocation expression) { + org.eclipse.jdt.internal.compiler.ast.ASTNode node = (org.eclipse.jdt.internal.compiler.ast.ASTNode) this.newAstToOldAst.get(expression); + if (node instanceof ExplicitConstructorCall) { + ExplicitConstructorCall explicitConstructorCall = (ExplicitConstructorCall) node; + return getMethodBinding(explicitConstructorCall.binding); + } + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.BindingResolver#resolveConstructor(org.eclipse.jdt.core.dom.EnumConstantDeclaration) + */ + IMethodBinding resolveConstructor(EnumConstantDeclaration enumConstantDeclaration) { + org.eclipse.jdt.internal.compiler.ast.ASTNode node = (org.eclipse.jdt.internal.compiler.ast.ASTNode) this.newAstToOldAst.get(enumConstantDeclaration); + if (node instanceof org.eclipse.jdt.internal.compiler.ast.FieldDeclaration) { + org.eclipse.jdt.internal.compiler.ast.FieldDeclaration fieldDeclaration = (org.eclipse.jdt.internal.compiler.ast.FieldDeclaration) node; + if (fieldDeclaration.getKind() == AbstractVariableDeclaration.ENUM_CONSTANT && fieldDeclaration.initialization != null) { + AllocationExpression allocationExpression = (AllocationExpression) fieldDeclaration.initialization; + return getMethodBinding(allocationExpression.binding); + } + } + return null; + } + + /* + * @see BindingResolver#resolveConstructor(SuperConstructorInvocation) + */ + synchronized IMethodBinding resolveConstructor(SuperConstructorInvocation expression) { + org.eclipse.jdt.internal.compiler.ast.ASTNode node = (org.eclipse.jdt.internal.compiler.ast.ASTNode) this.newAstToOldAst.get(expression); + if (node instanceof ExplicitConstructorCall) { + ExplicitConstructorCall explicitConstructorCall = (ExplicitConstructorCall) node; + return getMethodBinding(explicitConstructorCall.binding); + } + return null; + } + /* + * Method declared on BindingResolver. + */ + synchronized ITypeBinding resolveExpressionType(Expression expression) { + try { + switch(expression.getNodeType()) { + case ASTNode.CLASS_INSTANCE_CREATION : + org.eclipse.jdt.internal.compiler.ast.ASTNode astNode = (org.eclipse.jdt.internal.compiler.ast.ASTNode) this.newAstToOldAst.get(expression); + if (astNode instanceof org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) { + // anonymous type case + org.eclipse.jdt.internal.compiler.ast.TypeDeclaration typeDeclaration = (org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) astNode; + ITypeBinding typeBinding = this.getTypeBinding(typeDeclaration.binding); + if (typeBinding != null) { + return typeBinding; + } + } else if (astNode instanceof AllocationExpression) { + // should be an AllocationExpression + AllocationExpression allocationExpression = (AllocationExpression) astNode; + return this.getTypeBinding(allocationExpression.resolvedType); + } + break; + case ASTNode.SIMPLE_NAME : + case ASTNode.QUALIFIED_NAME : + return resolveTypeBindingForName((Name) expression); + case ASTNode.ARRAY_INITIALIZER : + case ASTNode.ARRAY_CREATION : + case ASTNode.ASSIGNMENT : + case ASTNode.POSTFIX_EXPRESSION : + case ASTNode.PREFIX_EXPRESSION : + case ASTNode.CAST_EXPRESSION : + case ASTNode.TYPE_LITERAL : + case ASTNode.INFIX_EXPRESSION : + case ASTNode.INSTANCEOF_EXPRESSION : + case ASTNode.FIELD_ACCESS : + case ASTNode.SUPER_FIELD_ACCESS : + case ASTNode.ARRAY_ACCESS : + case ASTNode.METHOD_INVOCATION : + case ASTNode.SUPER_METHOD_INVOCATION : + case ASTNode.CONDITIONAL_EXPRESSION : + case ASTNode.MARKER_ANNOTATION : + case ASTNode.NORMAL_ANNOTATION : + case ASTNode.SINGLE_MEMBER_ANNOTATION : + org.eclipse.jdt.internal.compiler.ast.Expression compilerExpression = (org.eclipse.jdt.internal.compiler.ast.Expression) this.newAstToOldAst.get(expression); + if (compilerExpression != null) { + return this.getTypeBinding(compilerExpression.resolvedType); + } + break; + case ASTNode.STRING_LITERAL : + if (this.scope != null) { + return this.getTypeBinding(this.scope.getJavaLangString()); + } + break; + case ASTNode.BOOLEAN_LITERAL : + case ASTNode.NULL_LITERAL : + case ASTNode.CHARACTER_LITERAL : + case ASTNode.NUMBER_LITERAL : + Literal literal = (Literal) this.newAstToOldAst.get(expression); + if (literal != null) { + return this.getTypeBinding(literal.literalType(null)); + } + break; + case ASTNode.THIS_EXPRESSION : + ThisReference thisReference = (ThisReference) this.newAstToOldAst.get(expression); + BlockScope blockScope = (BlockScope) this.astNodesToBlockScope.get(expression); + if (blockScope != null) { +//{ObjectTeams: calling into the compiler needs dependencies configured: + Dependencies.setup(this, null, lookupEnvironment(), false, false, false, true, true, false); + try { +// orig: + return this.getTypeBinding(thisReference.resolveType(blockScope)); +// :giro + } finally { + Dependencies.release(this); + } +// SH} + } + break; + case ASTNode.PARENTHESIZED_EXPRESSION : + ParenthesizedExpression parenthesizedExpression = (ParenthesizedExpression) expression; + return resolveExpressionType(parenthesizedExpression.getExpression()); + case ASTNode.VARIABLE_DECLARATION_EXPRESSION : + VariableDeclarationExpression variableDeclarationExpression = (VariableDeclarationExpression) expression; + Type type = variableDeclarationExpression.getType(); + if (type != null) { + return type.resolveBinding(); + } + break; + } + } catch (AbortCompilation e) { + // handle missing types + } + return null; + } + + /* + * @see BindingResolver#resolveField(FieldAccess) + */ + synchronized IVariableBinding resolveField(FieldAccess fieldAccess) { + Object oldNode = this.newAstToOldAst.get(fieldAccess); + if (oldNode instanceof FieldReference) { + FieldReference fieldReference = (FieldReference) oldNode; + return this.getVariableBinding(fieldReference.binding); + } + return null; + } + + /* + * @see BindingResolver#resolveField(SuperFieldAccess) + */ + synchronized IVariableBinding resolveField(SuperFieldAccess fieldAccess) { + Object oldNode = this.newAstToOldAst.get(fieldAccess); + if (oldNode instanceof FieldReference) { + FieldReference fieldReference = (FieldReference) oldNode; + return this.getVariableBinding(fieldReference.binding); + } + return null; + } + + /* + * @see BindingResolver#resolveImport(ImportDeclaration) + */ + synchronized IBinding resolveImport(ImportDeclaration importDeclaration) { + if (this.scope == null) return null; + try { + org.eclipse.jdt.internal.compiler.ast.ASTNode node = (org.eclipse.jdt.internal.compiler.ast.ASTNode) this.newAstToOldAst.get(importDeclaration); + if (node instanceof ImportReference) { + ImportReference importReference = (ImportReference) node; + final boolean isStatic = importReference.isStatic(); + if ((importReference.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.OnDemand) != 0) { + Binding binding = this.scope.getImport(CharOperation.subarray(importReference.tokens, 0, importReference.tokens.length), true, isStatic); + if (binding != null) { + if (isStatic) { + if (binding instanceof org.eclipse.jdt.internal.compiler.lookup.TypeBinding) { + ITypeBinding typeBinding = this.getTypeBinding((org.eclipse.jdt.internal.compiler.lookup.TypeBinding) binding); + return typeBinding == null ? null : typeBinding; + } + } else { + if ((binding.kind() & Binding.PACKAGE) != 0) { + IPackageBinding packageBinding = getPackageBinding((org.eclipse.jdt.internal.compiler.lookup.PackageBinding) binding); + if (packageBinding == null) { + return null; + } + return packageBinding; + } else { + // if it is not a package, it has to be a type + ITypeBinding typeBinding = this.getTypeBinding((org.eclipse.jdt.internal.compiler.lookup.TypeBinding) binding); + if (typeBinding == null) { + return null; + } + return typeBinding; + } + } + } + } else { + Binding binding = this.scope.getImport(importReference.tokens, false, isStatic); + if (binding != null) { + if (isStatic) { + if (binding instanceof org.eclipse.jdt.internal.compiler.lookup.TypeBinding) { + ITypeBinding typeBinding = this.getTypeBinding((org.eclipse.jdt.internal.compiler.lookup.TypeBinding) binding); + return typeBinding == null ? null : typeBinding; + } else if (binding instanceof FieldBinding) { + IVariableBinding variableBinding = this.getVariableBinding((FieldBinding) binding); + return variableBinding == null ? null : variableBinding; + } else if (binding instanceof org.eclipse.jdt.internal.compiler.lookup.MethodBinding) { + // it is a type + return getMethodBinding((org.eclipse.jdt.internal.compiler.lookup.MethodBinding)binding); + } + } else { + if (binding instanceof org.eclipse.jdt.internal.compiler.lookup.TypeBinding) { + ITypeBinding typeBinding = this.getTypeBinding((org.eclipse.jdt.internal.compiler.lookup.TypeBinding) binding); + return typeBinding == null ? null : typeBinding; + } + } + } + } + } + } catch(AbortCompilation e) { + // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=53357 + // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=63550 + // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=64299 + } + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.BindingResolver#resolveMember(org.eclipse.jdt.core.dom.AnnotationTypeMemberDeclaration) + */ + IMethodBinding resolveMember(AnnotationTypeMemberDeclaration declaration) { + Object oldNode = this.newAstToOldAst.get(declaration); + if (oldNode instanceof AbstractMethodDeclaration) { + AbstractMethodDeclaration methodDeclaration = (AbstractMethodDeclaration) oldNode; + IMethodBinding methodBinding = getMethodBinding(methodDeclaration.binding); + if (methodBinding == null) { + return null; + } + this.bindingsToAstNodes.put(methodBinding, declaration); + String key = methodBinding.getKey(); + if (key != null) { + this.bindingTables.bindingKeysToBindings.put(key, methodBinding); + } + return methodBinding; + } + return null; + } + + /* + * Method declared on BindingResolver. + */ + synchronized IMethodBinding resolveMethod(MethodDeclaration method) { + Object oldNode = this.newAstToOldAst.get(method); + if (oldNode instanceof AbstractMethodDeclaration) { + AbstractMethodDeclaration methodDeclaration = (AbstractMethodDeclaration) oldNode; + IMethodBinding methodBinding = getMethodBinding(methodDeclaration.binding); + if (methodBinding == null) { + return null; + } + this.bindingsToAstNodes.put(methodBinding, method); + String key = methodBinding.getKey(); + if (key != null) { + this.bindingTables.bindingKeysToBindings.put(key, methodBinding); + } + return methodBinding; + } + return null; + } + /* + * Method declared on BindingResolver. + */ + synchronized IMethodBinding resolveMethod(MethodInvocation method) { + Object oldNode = this.newAstToOldAst.get(method); + if (oldNode instanceof MessageSend) { + MessageSend messageSend = (MessageSend) oldNode; + return getMethodBinding(messageSend.binding); + } + return null; + } + /* + * Method declared on BindingResolver. + */ + synchronized IMethodBinding resolveMethod(SuperMethodInvocation method) { + Object oldNode = this.newAstToOldAst.get(method); + if (oldNode instanceof MessageSend) { + MessageSend messageSend = (MessageSend) oldNode; + return getMethodBinding(messageSend.binding); + } + return null; + } + +//{ObjectTeams: resolve bindings for OT-specific nodes + + synchronized IMethodBinding resolveConstructor(BaseConstructorInvocation constructor) + { + org.eclipse.jdt.internal.compiler.ast.ASTNode node = + (org.eclipse.jdt.internal.compiler.ast.ASTNode) this.newAstToOldAst.get(constructor); + if (node instanceof BaseAllocationExpression) + { + BaseAllocationExpression baseAllocExpr = + (BaseAllocationExpression)node; + AllocationExpression allocExpr = + (AllocationExpression)baseAllocExpr.expression; + return this.getMethodBinding(allocExpr.binding); + } + return null; + } + + synchronized IMethodBinding resolveConstructor(TSuperConstructorInvocation constructor) + { + org.eclipse.jdt.internal.compiler.ast.ASTNode node = + (org.eclipse.jdt.internal.compiler.ast.ASTNode)this.newAstToOldAst.get(constructor); + if (node instanceof ExplicitConstructorCall) + { + ExplicitConstructorCall explicitConstructorCall = (ExplicitConstructorCall)node; + return this.getMethodBinding(explicitConstructorCall.binding.copyInheritanceSrc); + } + return null; + } + + synchronized IMethodBinding resolveMethod(org.eclipse.jdt.core.dom.BaseCallMessageSend method) + { + org.eclipse.jdt.internal.compiler.ast.ASTNode node = + (org.eclipse.jdt.internal.compiler.ast.ASTNode)this.newAstToOldAst.get(method); + if (node instanceof BaseCallMessageSend) + { + BaseCallMessageSend baseCall = (BaseCallMessageSend)node; + return this.getMethodBinding(baseCall.getMessageSend().binding); + } + return null; + } + + synchronized IMethodBinding resolveMethod(org.eclipse.jdt.core.dom.MethodSpec method) + { + org.eclipse.jdt.internal.compiler.ast.ASTNode node = + (org.eclipse.jdt.internal.compiler.ast.ASTNode)this.newAstToOldAst.get(method); + + if (node instanceof MethodSpec) + { + MethodSpec methodSpec = (MethodSpec)node; + return this.getMethodBinding(methodSpec.resolvedMethod); + } + return null; + } + + synchronized IMethodBinding resolveMethod(org.eclipse.jdt.core.dom.TSuperMessageSend method) + { + org.eclipse.jdt.internal.compiler.ast.ASTNode node = + (org.eclipse.jdt.internal.compiler.ast.ASTNode)this.newAstToOldAst.get(method); + if (node instanceof TSuperMessageSend) + { + TSuperMessageSend msgSend = (TSuperMessageSend)node; + return this.getMethodBinding(msgSend.binding.copyInheritanceSrc); + } + return null; + } + + synchronized IMethodMappingBinding resolveMethodMapping(org.eclipse.jdt.core.dom.AbstractMethodMappingDeclaration mapping) + { + Object oldNode = this.newAstToOldAst.get(mapping); + if (oldNode instanceof AbstractMethodMappingDeclaration) { + AbstractMethodMappingDeclaration mappingDeclaration = (AbstractMethodMappingDeclaration) oldNode; + IMethodMappingBinding mappingBinding = this.getMethodMappingBinding(mappingDeclaration.binding); + if (mappingBinding == null) { + return null; + } + this.bindingsToAstNodes.put(mappingBinding, mapping); + String key = mappingBinding.getKey(); + if (key != null) { + this.bindingTables.bindingKeysToBindings.put(key, mappingBinding); + } + if (mappingDeclaration.isCallout() && mappingBinding.getRoleMethod() != null) { + // if role method is not present, register the callout for its stake: + key = mappingBinding.getRoleMethod().getKey(); + if (!this.bindingTables.bindingKeysToBindings.containsKey(key)) + this.bindingTables.bindingKeysToBindings.put(key, mappingBinding); + } + return mappingBinding; + } + return null; + } + + + + synchronized IVariableBinding resolveVariable(org.eclipse.jdt.core.dom.FieldAccessSpec field) + { + org.eclipse.jdt.internal.compiler.ast.ASTNode node = + (org.eclipse.jdt.internal.compiler.ast.ASTNode)this.newAstToOldAst.get(field); + if (node instanceof FieldAccessSpec) + { + FieldAccessSpec fieldAccessSpec = (FieldAccessSpec)node; + return this.getVariableBinding(fieldAccessSpec.resolvedField); + } + return null; + } +//mkr} + + synchronized ITypeBinding resolveTypeBindingForName(Name name) { + org.eclipse.jdt.internal.compiler.ast.ASTNode node = (org.eclipse.jdt.internal.compiler.ast.ASTNode) this.newAstToOldAst.get(name); + int index = name.index; + if (node instanceof QualifiedNameReference) { + QualifiedNameReference qualifiedNameReference = (QualifiedNameReference) node; + final char[][] tokens = qualifiedNameReference.tokens; + if (tokens.length == index) { + return this.getTypeBinding(qualifiedNameReference.resolvedType); + } + int indexOfFirstFieldBinding = qualifiedNameReference.indexOfFirstFieldBinding; // one-based + if (index < indexOfFirstFieldBinding) { + // an extra lookup is required + BlockScope internalScope = (BlockScope) this.astNodesToBlockScope.get(name); + Binding binding = null; + try { + if (internalScope == null) { + if (this.scope == null) return null; + binding = this.scope.getTypeOrPackage(CharOperation.subarray(tokens, 0, index)); + } else { + binding = internalScope.getTypeOrPackage(CharOperation.subarray(tokens, 0, index)); + } + } catch (AbortCompilation e) { + // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=53357 + // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=63550 + // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=64299 + } + if (binding instanceof org.eclipse.jdt.internal.compiler.lookup.PackageBinding) { + return null; + } else if (binding instanceof org.eclipse.jdt.internal.compiler.lookup.TypeBinding) { + // it is a type + return this.getTypeBinding((org.eclipse.jdt.internal.compiler.lookup.TypeBinding)binding); + } + } else if (index == indexOfFirstFieldBinding) { + if (qualifiedNameReference.isTypeReference()) { + return this.getTypeBinding(qualifiedNameReference.resolvedType); + } else { + // in this case we want to get the next field declaring's class + if (qualifiedNameReference.otherBindings == null) { + return null; + } + FieldBinding fieldBinding = qualifiedNameReference.otherBindings[0]; + if (fieldBinding == null) return null; + org.eclipse.jdt.internal.compiler.lookup.TypeBinding type = fieldBinding.declaringClass; + if (type == null) { // array length scenario + // use type from first binding (no capture needed for array type) + switch (qualifiedNameReference.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.RestrictiveFlagMASK) { + case Binding.FIELD: + type = ((FieldBinding) qualifiedNameReference.binding).type; + break; + case Binding.LOCAL: + type = ((LocalVariableBinding) qualifiedNameReference.binding).type; + break; + } + } + return this.getTypeBinding(type); + } + } else { + /* This is the case for a name which is part of a qualified name that + * cannot be resolved. See PR 13063. + */ + if (qualifiedNameReference.otherBindings == null) return null; + final int otherBindingsLength = qualifiedNameReference.otherBindings.length; + if (otherBindingsLength == (index - indexOfFirstFieldBinding)) { + return this.getTypeBinding(qualifiedNameReference.resolvedType); + } + FieldBinding fieldBinding = qualifiedNameReference.otherBindings[index - indexOfFirstFieldBinding]; + if (fieldBinding == null) return null; + org.eclipse.jdt.internal.compiler.lookup.TypeBinding type = fieldBinding.declaringClass; + if (type == null) { // array length scenario + // use type from previous binding (no capture needed for array type) + fieldBinding = qualifiedNameReference.otherBindings[index - indexOfFirstFieldBinding - 1]; + if (fieldBinding == null) return null; + type = fieldBinding.type; + } + return this.getTypeBinding(type); + } + } else if (node instanceof QualifiedTypeReference) { + QualifiedTypeReference qualifiedTypeReference = (QualifiedTypeReference) node; + if (qualifiedTypeReference.resolvedType == null) { + return null; + } + if (index == qualifiedTypeReference.tokens.length) { + if (!qualifiedTypeReference.resolvedType.isValidBinding() && qualifiedTypeReference instanceof JavadocQualifiedTypeReference) { + JavadocQualifiedTypeReference typeRef = (JavadocQualifiedTypeReference) node; + if (typeRef.packageBinding != null) { + return null; + } + } + return this.getTypeBinding(qualifiedTypeReference.resolvedType.leafComponentType()); + } else { + if (index >= 0) { + BlockScope internalScope = (BlockScope) this.astNodesToBlockScope.get(name); + Binding binding = null; + try { + if (internalScope == null) { + if (this.scope == null) return null; + binding = this.scope.getTypeOrPackage(CharOperation.subarray(qualifiedTypeReference.tokens, 0, index)); + } else { + binding = internalScope.getTypeOrPackage(CharOperation.subarray(qualifiedTypeReference.tokens, 0, index)); + } + } catch (AbortCompilation e) { + // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=53357 + } + if (binding instanceof org.eclipse.jdt.internal.compiler.lookup.PackageBinding) { + return null; + } else if (binding instanceof org.eclipse.jdt.internal.compiler.lookup.TypeBinding) { + // it is a type + return this.getTypeBinding((org.eclipse.jdt.internal.compiler.lookup.TypeBinding)binding); + } else { + return null; + } + } + } + } else if (node instanceof ImportReference) { + ImportReference importReference = (ImportReference) node; + int importReferenceLength = importReference.tokens.length; + if (index >= 0) { + Binding binding = null; + if (this.scope == null) return null; + if (importReferenceLength == index) { + try { + binding = this.scope.getImport(CharOperation.subarray(importReference.tokens, 0, index), (importReference.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.OnDemand) != 0, importReference.isStatic()); + } catch (AbortCompilation e) { + // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=53357 + } + } else { + try { + binding = this.scope.getImport(CharOperation.subarray(importReference.tokens, 0, index), true, importReference.isStatic()); + } catch (AbortCompilation e) { + // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=53357 + } + } + if (binding != null) { + if (binding instanceof org.eclipse.jdt.internal.compiler.lookup.TypeBinding) { + // it is a type + return this.getTypeBinding((org.eclipse.jdt.internal.compiler.lookup.TypeBinding)binding); + } + return null; + } + } + } else if (node instanceof AbstractMethodDeclaration) { + AbstractMethodDeclaration methodDeclaration = (AbstractMethodDeclaration) node; + IMethodBinding method = getMethodBinding(methodDeclaration.binding); + if (method == null) return null; + return method.getReturnType(); + } else if (node instanceof org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) { + org.eclipse.jdt.internal.compiler.ast.TypeDeclaration typeDeclaration = (org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) node; + ITypeBinding typeBinding = this.getTypeBinding(typeDeclaration.binding); + if (typeBinding != null) { + return typeBinding; + } + } if (node instanceof JavadocSingleNameReference) { + JavadocSingleNameReference singleNameReference = (JavadocSingleNameReference) node; + LocalVariableBinding localVariable = (LocalVariableBinding)singleNameReference.binding; + if (localVariable != null) { + return this.getTypeBinding(localVariable.type); + } + } if (node instanceof SingleNameReference) { + SingleNameReference singleNameReference = (SingleNameReference) node; + return this.getTypeBinding(singleNameReference.resolvedType); + } else if (node instanceof QualifiedSuperReference) { + QualifiedSuperReference qualifiedSuperReference = (QualifiedSuperReference) node; + return this.getTypeBinding(qualifiedSuperReference.qualification.resolvedType); + } else if (node instanceof LocalDeclaration) { + IVariableBinding variable = this.getVariableBinding(((LocalDeclaration)node).binding); + if (variable == null) return null; + return variable.getType(); + } else if (node instanceof JavadocFieldReference) { + JavadocFieldReference fieldRef = (JavadocFieldReference) node; + if (fieldRef.methodBinding != null) { + return getMethodBinding(fieldRef.methodBinding).getReturnType(); + } + return getTypeBinding(fieldRef.resolvedType); + } else if (node instanceof FieldReference) { + return getTypeBinding(((FieldReference) node).resolvedType); + } else if (node instanceof SingleTypeReference) { + SingleTypeReference singleTypeReference = (SingleTypeReference) node; + org.eclipse.jdt.internal.compiler.lookup.TypeBinding binding = singleTypeReference.resolvedType; + if (binding != null) { + return this.getTypeBinding(binding.leafComponentType()); + } + } else if (node instanceof org.eclipse.jdt.internal.compiler.ast.FieldDeclaration) { + org.eclipse.jdt.internal.compiler.ast.FieldDeclaration fieldDeclaration = (org.eclipse.jdt.internal.compiler.ast.FieldDeclaration) node; + IVariableBinding field = this.getVariableBinding(fieldDeclaration.binding); + if (field == null) return null; + return field.getType(); + } else if (node instanceof MessageSend) { + MessageSend messageSend = (MessageSend) node; + IMethodBinding method = getMethodBinding(messageSend.binding); + if (method == null) return null; + return method.getReturnType(); + } else if (node instanceof AllocationExpression) { + AllocationExpression allocation = (AllocationExpression) node; + return getTypeBinding(allocation.resolvedType); + } else if (node instanceof JavadocImplicitTypeReference) { + JavadocImplicitTypeReference implicitRef = (JavadocImplicitTypeReference) node; + return getTypeBinding(implicitRef.resolvedType); + } else if (node instanceof org.eclipse.jdt.internal.compiler.ast.TypeParameter) { + org.eclipse.jdt.internal.compiler.ast.TypeParameter typeParameter = (org.eclipse.jdt.internal.compiler.ast.TypeParameter) node; + return this.getTypeBinding(typeParameter.binding); + } else if (node instanceof org.eclipse.jdt.internal.compiler.ast.MemberValuePair) { + org.eclipse.jdt.internal.compiler.ast.MemberValuePair memberValuePair = (org.eclipse.jdt.internal.compiler.ast.MemberValuePair) node; + IMethodBinding method = getMethodBinding(memberValuePair.binding); + if (method == null) return null; + return method.getReturnType(); + } + return null; + } + + /* + * Method declared on BindingResolver. + */ + synchronized IBinding resolveName(Name name) { + org.eclipse.jdt.internal.compiler.ast.ASTNode node = (org.eclipse.jdt.internal.compiler.ast.ASTNode) this.newAstToOldAst.get(name); + int index = name.index; + if (node instanceof QualifiedNameReference) { + QualifiedNameReference qualifiedNameReference = (QualifiedNameReference) node; + final char[][] tokens = qualifiedNameReference.tokens; + int indexOfFirstFieldBinding = qualifiedNameReference.indexOfFirstFieldBinding; // one-based + if (index < indexOfFirstFieldBinding) { + // an extra lookup is required + BlockScope internalScope = (BlockScope) this.astNodesToBlockScope.get(name); + Binding binding = null; + try { + if (internalScope == null) { + if (this.scope == null) return null; + binding = this.scope.getTypeOrPackage(CharOperation.subarray(tokens, 0, index)); + } else { + binding = internalScope.getTypeOrPackage(CharOperation.subarray(tokens, 0, index)); + } + } catch (AbortCompilation e) { + // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=53357 + // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=63550 + // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=64299 + } + if (binding instanceof org.eclipse.jdt.internal.compiler.lookup.PackageBinding) { + return getPackageBinding((org.eclipse.jdt.internal.compiler.lookup.PackageBinding)binding); + } else if (binding instanceof org.eclipse.jdt.internal.compiler.lookup.TypeBinding) { + // it is a type + return this.getTypeBinding((org.eclipse.jdt.internal.compiler.lookup.TypeBinding)binding); + } + } else if (index == indexOfFirstFieldBinding) { + if (qualifiedNameReference.isTypeReference()) { + return this.getTypeBinding(qualifiedNameReference.resolvedType); + } else { + Binding binding = qualifiedNameReference.binding; + if (binding != null) { + if (binding.isValidBinding()) { + return this.getVariableBinding((org.eclipse.jdt.internal.compiler.lookup.VariableBinding) binding); + } else if (binding instanceof ProblemFieldBinding) { + ProblemFieldBinding problemFieldBinding = (ProblemFieldBinding) binding; + switch(problemFieldBinding.problemId()) { + case ProblemReasons.NotVisible : + case ProblemReasons.NonStaticReferenceInStaticContext : + ReferenceBinding declaringClass = problemFieldBinding.declaringClass; + if (declaringClass != null) { + FieldBinding exactBinding = declaringClass.getField(tokens[tokens.length - 1], true /*resolve*/); + if (exactBinding != null) { + if (exactBinding.type != null) { + IVariableBinding variableBinding = (IVariableBinding) this.bindingTables.compilerBindingsToASTBindings.get(exactBinding); + if (variableBinding != null) { + return variableBinding; + } + variableBinding = new VariableBinding(this, exactBinding); + this.bindingTables.compilerBindingsToASTBindings.put(exactBinding, variableBinding); + return variableBinding; + } + } + } + break; + } + } + } + } + } else { + /* This is the case for a name which is part of a qualified name that + * cannot be resolved. See PR 13063. + */ + if (qualifiedNameReference.otherBindings == null || (index - indexOfFirstFieldBinding - 1) < 0) { + return null; + } else { + return this.getVariableBinding(qualifiedNameReference.otherBindings[index - indexOfFirstFieldBinding - 1]); + } + } + } else if (node instanceof QualifiedTypeReference) { + QualifiedTypeReference qualifiedTypeReference = (QualifiedTypeReference) node; + if (qualifiedTypeReference.resolvedType == null) { + return null; + } + if (index == qualifiedTypeReference.tokens.length) { + if (!qualifiedTypeReference.resolvedType.isValidBinding() && qualifiedTypeReference instanceof JavadocQualifiedTypeReference) { + JavadocQualifiedTypeReference typeRef = (JavadocQualifiedTypeReference) node; + if (typeRef.packageBinding != null) { + return getPackageBinding(typeRef.packageBinding); + } + } + return this.getTypeBinding(qualifiedTypeReference.resolvedType.leafComponentType()); + } else { + if (index >= 0) { + BlockScope internalScope = (BlockScope) this.astNodesToBlockScope.get(name); + Binding binding = null; + try { + if (internalScope == null) { + if (this.scope == null) return null; + binding = this.scope.getTypeOrPackage(CharOperation.subarray(qualifiedTypeReference.tokens, 0, index)); + } else { + binding = internalScope.getTypeOrPackage(CharOperation.subarray(qualifiedTypeReference.tokens, 0, index)); + } + } catch (AbortCompilation e) { + // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=53357 + } + if (binding instanceof org.eclipse.jdt.internal.compiler.lookup.PackageBinding) { + return getPackageBinding((org.eclipse.jdt.internal.compiler.lookup.PackageBinding)binding); + } else if (binding instanceof org.eclipse.jdt.internal.compiler.lookup.TypeBinding) { + // it is a type + return this.getTypeBinding((org.eclipse.jdt.internal.compiler.lookup.TypeBinding)binding); + } else { + return null; + } + } + } + } else if (node instanceof ImportReference) { + ImportReference importReference = (ImportReference) node; + int importReferenceLength = importReference.tokens.length; + if (index >= 0) { + Binding binding = null; + if (this.scope == null) return null; + if (importReferenceLength == index) { + try { + binding = this.scope.getImport(CharOperation.subarray(importReference.tokens, 0, index), (importReference.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.OnDemand) != 0, importReference.isStatic()); + } catch (AbortCompilation e) { + // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=53357 + } + } else { + try { + binding = this.scope.getImport(CharOperation.subarray(importReference.tokens, 0, index), true, importReference.isStatic()); + } catch (AbortCompilation e) { + // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=53357 + } + } + if (binding != null) { + if (binding instanceof org.eclipse.jdt.internal.compiler.lookup.PackageBinding) { + return getPackageBinding((org.eclipse.jdt.internal.compiler.lookup.PackageBinding)binding); + } else if (binding instanceof org.eclipse.jdt.internal.compiler.lookup.TypeBinding) { + // it is a type + return this.getTypeBinding((org.eclipse.jdt.internal.compiler.lookup.TypeBinding)binding); + } else if (binding instanceof org.eclipse.jdt.internal.compiler.lookup.FieldBinding) { + // it is a type + return this.getVariableBinding((org.eclipse.jdt.internal.compiler.lookup.FieldBinding)binding); + } else if (binding instanceof org.eclipse.jdt.internal.compiler.lookup.MethodBinding) { + // it is a type + return getMethodBinding((org.eclipse.jdt.internal.compiler.lookup.MethodBinding)binding); + } else { + return null; + } + } + } + } else if (node instanceof CompilationUnitDeclaration) { + CompilationUnitDeclaration compilationUnitDeclaration = (CompilationUnitDeclaration) node; + org.eclipse.jdt.internal.compiler.ast.TypeDeclaration[] types = compilationUnitDeclaration.types; + if (types == null || types.length == 0) { + return null; + } + org.eclipse.jdt.internal.compiler.ast.TypeDeclaration type = types[0]; + if (type != null) { + ITypeBinding typeBinding = this.getTypeBinding(type.binding); + if (typeBinding != null) { + return typeBinding.getPackage(); + } + } + } else if (node instanceof AbstractMethodDeclaration) { + AbstractMethodDeclaration methodDeclaration = (AbstractMethodDeclaration) node; + IMethodBinding methodBinding = getMethodBinding(methodDeclaration.binding); + if (methodBinding != null) { + return methodBinding; + } + } else if (node instanceof org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) { + org.eclipse.jdt.internal.compiler.ast.TypeDeclaration typeDeclaration = (org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) node; + ITypeBinding typeBinding = this.getTypeBinding(typeDeclaration.binding); + if (typeBinding != null) { + return typeBinding; + } + } if (node instanceof SingleNameReference) { + SingleNameReference singleNameReference = (SingleNameReference) node; + if (singleNameReference.isTypeReference()) { + return this.getTypeBinding(singleNameReference.resolvedType); + } else { + // this is a variable or a field + Binding binding = singleNameReference.binding; +//{ObjectTeams: if binding is an internal local variable of a callin/callout wrapper try to find the actual surface element: + binding = CallinCalloutScope.maybeReResolveReference(singleNameReference, binding); +// SH} + if (binding != null) { + if (binding.isValidBinding()) { + return this.getVariableBinding((org.eclipse.jdt.internal.compiler.lookup.VariableBinding) binding); + } else { + /* + * http://dev.eclipse.org/bugs/show_bug.cgi?id=24449 + */ + if (binding instanceof ProblemFieldBinding) { + ProblemFieldBinding problemFieldBinding = (ProblemFieldBinding) binding; + switch(problemFieldBinding.problemId()) { + case ProblemReasons.NotVisible : + case ProblemReasons.NonStaticReferenceInStaticContext : + case ProblemReasons.NonStaticReferenceInConstructorInvocation : + ReferenceBinding declaringClass = problemFieldBinding.declaringClass; + FieldBinding exactBinding = declaringClass.getField(problemFieldBinding.name, true /*resolve*/); + if (exactBinding != null) { + if (exactBinding.type != null) { + IVariableBinding variableBinding2 = (IVariableBinding) this.bindingTables.compilerBindingsToASTBindings.get(exactBinding); + if (variableBinding2 != null) { + return variableBinding2; + } + variableBinding2 = new VariableBinding(this, exactBinding); + this.bindingTables.compilerBindingsToASTBindings.put(exactBinding, variableBinding2); + return variableBinding2; + } + } + break; + } + } + } + } + } + } else if (node instanceof QualifiedSuperReference) { + QualifiedSuperReference qualifiedSuperReference = (QualifiedSuperReference) node; + return this.getTypeBinding(qualifiedSuperReference.qualification.resolvedType); + } else if (node instanceof LocalDeclaration) { + return this.getVariableBinding(((LocalDeclaration)node).binding); + } else if (node instanceof JavadocFieldReference) { + JavadocFieldReference fieldRef = (JavadocFieldReference) node; + if (fieldRef.methodBinding != null) { + return getMethodBinding(fieldRef.methodBinding); + } + return getVariableBinding(fieldRef.binding); + } else if (node instanceof FieldReference) { + return getVariableBinding(((FieldReference) node).binding); + } else if (node instanceof SingleTypeReference) { + if (node instanceof JavadocSingleTypeReference) { + JavadocSingleTypeReference typeRef = (JavadocSingleTypeReference) node; + if (typeRef.packageBinding != null) { + return getPackageBinding(typeRef.packageBinding); + } + } + SingleTypeReference singleTypeReference = (SingleTypeReference) node; + org.eclipse.jdt.internal.compiler.lookup.TypeBinding binding = singleTypeReference.resolvedType; + if (binding == null) { + return null; + } + return this.getTypeBinding(binding.leafComponentType()); + } else if (node instanceof org.eclipse.jdt.internal.compiler.ast.FieldDeclaration) { + org.eclipse.jdt.internal.compiler.ast.FieldDeclaration fieldDeclaration = (org.eclipse.jdt.internal.compiler.ast.FieldDeclaration) node; + return this.getVariableBinding(fieldDeclaration.binding); + } else if (node instanceof MessageSend) { + MessageSend messageSend = (MessageSend) node; + return getMethodBinding(messageSend.binding); + } else if (node instanceof AllocationExpression) { + AllocationExpression allocation = (AllocationExpression) node; + return getMethodBinding(allocation.binding); + } else if (node instanceof JavadocImplicitTypeReference) { + JavadocImplicitTypeReference implicitRef = (JavadocImplicitTypeReference) node; + return getTypeBinding(implicitRef.resolvedType); + } else if (node instanceof org.eclipse.jdt.internal.compiler.ast.TypeParameter) { + org.eclipse.jdt.internal.compiler.ast.TypeParameter typeParameter = (org.eclipse.jdt.internal.compiler.ast.TypeParameter) node; + return this.getTypeBinding(typeParameter.binding); + } else if (node instanceof org.eclipse.jdt.internal.compiler.ast.MemberValuePair) { + org.eclipse.jdt.internal.compiler.ast.MemberValuePair memberValuePair = (org.eclipse.jdt.internal.compiler.ast.MemberValuePair) node; + return getMethodBinding(memberValuePair.binding); + } +//{ObjectTeams: Resolve bindings for OT-specific elements + else if (node instanceof MethodSpec) + { + if (!(node instanceof FieldAccessSpec)) + { + MethodSpec methodSpec = (MethodSpec)node; + return getMethodBinding(methodSpec.resolvedMethod); + } + else + { + FieldAccessSpec fieldAccessSpec = (FieldAccessSpec) node; + return getVariableBinding(fieldAccessSpec.resolvedField); + } + } + else if (node instanceof LiftingTypeReference) + { + LiftingTypeReference liftingTypeRef = (LiftingTypeReference)node; + return getTypeBinding(liftingTypeRef.resolvedType); + } +//jsv} + return null; + } + + /* + * @see BindingResolver#resolvePackage(PackageDeclaration) + */ + synchronized IPackageBinding resolvePackage(PackageDeclaration pkg) { + if (this.scope == null) return null; + try { + org.eclipse.jdt.internal.compiler.ast.ASTNode node = (org.eclipse.jdt.internal.compiler.ast.ASTNode) this.newAstToOldAst.get(pkg); + if (node instanceof ImportReference) { + ImportReference importReference = (ImportReference) node; + Binding binding = this.scope.getTypeOrPackage(CharOperation.subarray(importReference.tokens, 0, importReference.tokens.length)); + if ((binding != null) && (binding.isValidBinding())) { + if (binding instanceof ReferenceBinding) { + // this only happens if a type name has the same name as its package + ReferenceBinding referenceBinding = (ReferenceBinding) binding; +//{ObjectTeams: team packages replace the team type with the package + binding= referenceBinding.teamPackage; + if (binding == null) // only if team package didn't work go back to JDT strategy: +// SH} + binding = referenceBinding.fPackage; + } + if (binding instanceof org.eclipse.jdt.internal.compiler.lookup.PackageBinding) { + IPackageBinding packageBinding = getPackageBinding((org.eclipse.jdt.internal.compiler.lookup.PackageBinding) binding); + if (packageBinding == null) { + return null; + } + this.bindingsToAstNodes.put(packageBinding, pkg); + String key = packageBinding.getKey(); + if (key != null) { + this.bindingTables.bindingKeysToBindings.put(key, packageBinding); + } + return packageBinding; + } + } + } + } catch (AbortCompilation e) { + // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=53357 + // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=63550 + // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=64299 + } + return null; + } + + /* (non-Javadoc) + * @see BindingResolver#resolveReference(MemberRef) + * @since 3.0 + */ + synchronized IBinding resolveReference(MemberRef ref) { + org.eclipse.jdt.internal.compiler.ast.Expression expression = (org.eclipse.jdt.internal.compiler.ast.Expression) this.newAstToOldAst.get(ref); + if (expression instanceof TypeReference) { + return getTypeBinding(expression.resolvedType); + } else if (expression instanceof JavadocFieldReference) { + JavadocFieldReference fieldRef = (JavadocFieldReference) expression; + if (fieldRef.methodBinding != null) { + return getMethodBinding(fieldRef.methodBinding); + } + return getVariableBinding(fieldRef.binding); + } + return null; + } + + /* (non-Javadoc) + * @see BindingResolver#resolveMemberValuePair(MemberValuePair) + * @since 3.2 + */ + synchronized IMemberValuePairBinding resolveMemberValuePair(org.eclipse.jdt.core.dom.MemberValuePair memberValuePair) { + MemberValuePair valuePair = (MemberValuePair) this.newAstToOldAst.get(memberValuePair); + if (valuePair != null) { + return getMemberValuePairBinding(valuePair.compilerElementPair); + } + return null; + } + + /* (non-Javadoc) + * @see BindingResolver#resolveReference(MethodRef) + * @since 3.0 + */ + synchronized IBinding resolveReference(MethodRef ref) { + org.eclipse.jdt.internal.compiler.ast.Expression expression = (org.eclipse.jdt.internal.compiler.ast.Expression) this.newAstToOldAst.get(ref); + if (expression instanceof JavadocMessageSend) { + return getMethodBinding(((JavadocMessageSend)expression).binding); + } + else if (expression instanceof JavadocAllocationExpression) { + return getMethodBinding(((JavadocAllocationExpression)expression).binding); + } + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.BindingResolver#resolveType(org.eclipse.jdt.core.dom.AnnotationTypeDeclaration) + */ + ITypeBinding resolveType(AnnotationTypeDeclaration type) { + final Object node = this.newAstToOldAst.get(type); + if (node instanceof org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) { + org.eclipse.jdt.internal.compiler.ast.TypeDeclaration typeDeclaration = (org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) node; + ITypeBinding typeBinding = this.getTypeBinding(typeDeclaration.binding); + if (typeBinding == null) { + return null; + } + this.bindingsToAstNodes.put(typeBinding, type); + String key = typeBinding.getKey(); + if (key != null) { + this.bindingTables.bindingKeysToBindings.put(key, typeBinding); + } + return typeBinding; + } + return null; + } + /* + * @see BindingResolver#resolveType(AnonymousClassDeclaration) + */ + synchronized ITypeBinding resolveType(AnonymousClassDeclaration type) { + org.eclipse.jdt.internal.compiler.ast.ASTNode node = (org.eclipse.jdt.internal.compiler.ast.ASTNode) this.newAstToOldAst.get(type); + if (node != null && (node.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.IsAnonymousType) != 0) { + org.eclipse.jdt.internal.compiler.ast.TypeDeclaration anonymousLocalTypeDeclaration = (org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) node; + ITypeBinding typeBinding = this.getTypeBinding(anonymousLocalTypeDeclaration.binding); + if (typeBinding == null) { + return null; + } + this.bindingsToAstNodes.put(typeBinding, type); + String key = typeBinding.getKey(); + if (key != null) { + this.bindingTables.bindingKeysToBindings.put(key, typeBinding); + } + return typeBinding; + } + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.BindingResolver#resolveType(org.eclipse.jdt.core.dom.EnumDeclaration) + */ + ITypeBinding resolveType(EnumDeclaration type) { + final Object node = this.newAstToOldAst.get(type); + if (node instanceof org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) { + org.eclipse.jdt.internal.compiler.ast.TypeDeclaration typeDeclaration = (org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) node; + ITypeBinding typeBinding = this.getTypeBinding(typeDeclaration.binding); + if (typeBinding == null) { + return null; + } + this.bindingsToAstNodes.put(typeBinding, type); + String key = typeBinding.getKey(); + if (key != null) { + this.bindingTables.bindingKeysToBindings.put(key, typeBinding); + } + return typeBinding; + } + return null; + } + + /* + * Method declared on BindingResolver. + */ + synchronized ITypeBinding resolveType(Type type) { + // retrieve the old ast node + org.eclipse.jdt.internal.compiler.ast.ASTNode node = (org.eclipse.jdt.internal.compiler.ast.ASTNode) this.newAstToOldAst.get(type); + org.eclipse.jdt.internal.compiler.lookup.TypeBinding binding = null; + if (node != null) { + if (node instanceof ParameterizedQualifiedTypeReference) { + ParameterizedQualifiedTypeReference typeReference = (ParameterizedQualifiedTypeReference) node; + org.eclipse.jdt.internal.compiler.lookup.TypeBinding typeBinding = typeReference.resolvedType; + int index; + if (type.isQualifiedType()) { + index = ((QualifiedType) type).index; + } else if (type.isParameterizedType()) { + index = ((ParameterizedType) type).index; + } else { + index = 1; + } + final int numberOfTypeArgumentsNotNull = getTypeArguments(typeReference); + if (index != numberOfTypeArgumentsNotNull) { + int i = numberOfTypeArgumentsNotNull; + while (i != index) { + typeBinding = typeBinding.enclosingType(); + i --; + } + binding = typeBinding; + } else { + binding = typeBinding; + } + } else if (node instanceof TypeReference) { + TypeReference typeReference = (TypeReference) node; + binding = typeReference.resolvedType; + } else if (node instanceof SingleNameReference && ((SingleNameReference)node).isTypeReference()) { + binding = (((SingleNameReference)node).resolvedType); + } else if (node instanceof QualifiedNameReference && ((QualifiedNameReference)node).isTypeReference()) { + binding = (((QualifiedNameReference)node).resolvedType); + } else if (node instanceof ArrayAllocationExpression) { + binding = ((ArrayAllocationExpression) node).resolvedType; + } + if (binding != null) { + if (type.isArrayType()) { + ArrayType arrayType = (ArrayType) type; + if (this.scope == null) return null; + if (binding.isArrayType()) { + ArrayBinding arrayBinding = (ArrayBinding) binding; + return getTypeBinding(this.scope.createArrayType(arrayBinding.leafComponentType, arrayType.getDimensions())); + } else { + return getTypeBinding(this.scope.createArrayType(binding, arrayType.getDimensions())); + } + } else { + if (binding.isArrayType()) { + ArrayBinding arrayBinding = (ArrayBinding) binding; + return getTypeBinding(arrayBinding.leafComponentType); + } else { + return getTypeBinding(binding); + } + } + } + } else if (type.isPrimitiveType()) { + /* Handle the void primitive type returned by getReturnType for a method declaration + * that is a constructor declaration. It prevents null from being returned + */ + if (((PrimitiveType) type).getPrimitiveTypeCode() == PrimitiveType.VOID) { + return this.getTypeBinding(org.eclipse.jdt.internal.compiler.lookup.TypeBinding.VOID); + } + } + return null; + } + + /* + * Method declared on BindingResolver. + */ + synchronized ITypeBinding resolveType(TypeDeclaration type) { + final Object node = this.newAstToOldAst.get(type); + if (node instanceof org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) { + org.eclipse.jdt.internal.compiler.ast.TypeDeclaration typeDeclaration = (org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) node; + ITypeBinding typeBinding = this.getTypeBinding(typeDeclaration.binding); + if (typeBinding == null) { + return null; + } + this.bindingsToAstNodes.put(typeBinding, type); + String key = typeBinding.getKey(); + if (key != null) { + this.bindingTables.bindingKeysToBindings.put(key, typeBinding); + } + return typeBinding; + } + return null; + } + + synchronized ITypeBinding resolveTypeParameter(TypeParameter typeParameter) { + final Object node = this.newAstToOldAst.get(typeParameter); + if (node instanceof org.eclipse.jdt.internal.compiler.ast.TypeParameter) { + org.eclipse.jdt.internal.compiler.ast.TypeParameter typeParameter2 = (org.eclipse.jdt.internal.compiler.ast.TypeParameter) node; + ITypeBinding typeBinding = this.getTypeBinding(typeParameter2.binding); + if (typeBinding == null) { + return null; + } + this.bindingsToAstNodes.put(typeBinding, typeParameter); + String key = typeBinding.getKey(); + if (key != null) { + this.bindingTables.bindingKeysToBindings.put(key, typeBinding); + } + return typeBinding; + } + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.BindingResolver#resolveVariable(org.eclipse.jdt.core.dom.EnumConstantDeclaration) + */ + synchronized IVariableBinding resolveVariable(EnumConstantDeclaration enumConstant) { + final Object node = this.newAstToOldAst.get(enumConstant); + if (node instanceof org.eclipse.jdt.internal.compiler.ast.FieldDeclaration) { + org.eclipse.jdt.internal.compiler.ast.FieldDeclaration fieldDeclaration = (org.eclipse.jdt.internal.compiler.ast.FieldDeclaration) node; + IVariableBinding variableBinding = this.getVariableBinding(fieldDeclaration.binding); + if (variableBinding == null) { + return null; + } + this.bindingsToAstNodes.put(variableBinding, enumConstant); + String key = variableBinding.getKey(); + if (key != null) { + this.bindingTables.bindingKeysToBindings.put(key, variableBinding); + } + return variableBinding; + } + return null; + } + /* + * Method declared on BindingResolver. + */ + synchronized IVariableBinding resolveVariable(VariableDeclaration variable) { + final Object node = this.newAstToOldAst.get(variable); + if (node instanceof AbstractVariableDeclaration) { + AbstractVariableDeclaration abstractVariableDeclaration = (AbstractVariableDeclaration) node; + IVariableBinding variableBinding = null; + if (abstractVariableDeclaration instanceof org.eclipse.jdt.internal.compiler.ast.FieldDeclaration) { + org.eclipse.jdt.internal.compiler.ast.FieldDeclaration fieldDeclaration = (org.eclipse.jdt.internal.compiler.ast.FieldDeclaration) abstractVariableDeclaration; + variableBinding = this.getVariableBinding(fieldDeclaration.binding, variable); + } else { + variableBinding = this.getVariableBinding(((LocalDeclaration) abstractVariableDeclaration).binding, variable); + } + if (variableBinding == null) { + return null; + } + this.bindingsToAstNodes.put(variableBinding, variable); + String key = variableBinding.getKey(); + if (key != null) { + this.bindingTables.bindingKeysToBindings.put(key, variableBinding); + } + return variableBinding; + } + return null; + } + + /* + * Method declared on BindingResolver. + */ + synchronized ITypeBinding resolveWellKnownType(String name) { + if (this.scope == null) return null; + ITypeBinding typeBinding = null; + try { + if (("boolean".equals(name))//$NON-NLS-1$ + || ("char".equals(name))//$NON-NLS-1$ + || ("byte".equals(name))//$NON-NLS-1$ + || ("short".equals(name))//$NON-NLS-1$ + || ("int".equals(name))//$NON-NLS-1$ + || ("long".equals(name))//$NON-NLS-1$ + || ("float".equals(name))//$NON-NLS-1$ + || ("double".equals(name))//$NON-NLS-1$ + || ("void".equals(name))) {//$NON-NLS-1$ + typeBinding = this.getTypeBinding(Scope.getBaseType(name.toCharArray())); + } else if ("java.lang.Object".equals(name)) {//$NON-NLS-1$ + typeBinding = this.getTypeBinding(this.scope.getJavaLangObject()); + } else if ("java.lang.String".equals(name)) {//$NON-NLS-1$ + typeBinding = this.getTypeBinding(this.scope.getJavaLangString()); + } else if ("java.lang.StringBuffer".equals(name)) {//$NON-NLS-1$ + typeBinding = this.getTypeBinding(this.scope.getType(TypeConstants.JAVA_LANG_STRINGBUFFER, 3)); + } else if ("java.lang.Throwable".equals(name)) {//$NON-NLS-1$ + typeBinding = this.getTypeBinding(this.scope.getJavaLangThrowable()); + } else if ("java.lang.Exception".equals(name)) {//$NON-NLS-1$ + typeBinding = this.getTypeBinding(this.scope.getType(TypeConstants.JAVA_LANG_EXCEPTION, 3)); + } else if ("java.lang.RuntimeException".equals(name)) {//$NON-NLS-1$ + typeBinding = this.getTypeBinding(this.scope.getType(TypeConstants.JAVA_LANG_RUNTIMEEXCEPTION, 3)); + } else if ("java.lang.Error".equals(name)) {//$NON-NLS-1$ + typeBinding = this.getTypeBinding(this.scope.getType(TypeConstants.JAVA_LANG_ERROR, 3)); + } else if ("java.lang.Class".equals(name)) {//$NON-NLS-1$ + typeBinding = this.getTypeBinding(this.scope.getJavaLangClass()); + } else if ("java.lang.Cloneable".equals(name)) {//$NON-NLS-1$ + typeBinding = this.getTypeBinding(this.scope.getJavaLangCloneable()); + } else if ("java.io.Serializable".equals(name)) {//$NON-NLS-1$ + typeBinding = this.getTypeBinding(this.scope.getJavaIoSerializable()); + } else if ("java.lang.Boolean".equals(name)) {//$NON-NLS-1$ + typeBinding = this.getTypeBinding(this.scope.getType(TypeConstants.JAVA_LANG_BOOLEAN, 3)); + } else if ("java.lang.Byte".equals(name)) {//$NON-NLS-1$ + typeBinding = this.getTypeBinding(this.scope.getType(TypeConstants.JAVA_LANG_BYTE, 3)); + } else if ("java.lang.Character".equals(name)) {//$NON-NLS-1$ + typeBinding = this.getTypeBinding(this.scope.getType(TypeConstants.JAVA_LANG_CHARACTER, 3)); + } else if ("java.lang.Double".equals(name)) {//$NON-NLS-1$ + typeBinding = this.getTypeBinding(this.scope.getType(TypeConstants.JAVA_LANG_DOUBLE, 3)); + } else if ("java.lang.Float".equals(name)) {//$NON-NLS-1$ + typeBinding = this.getTypeBinding(this.scope.getType(TypeConstants.JAVA_LANG_FLOAT, 3)); + } else if ("java.lang.Integer".equals(name)) {//$NON-NLS-1$ + typeBinding = this.getTypeBinding(this.scope.getType(TypeConstants.JAVA_LANG_INTEGER, 3)); + } else if ("java.lang.Long".equals(name)) {//$NON-NLS-1$ + typeBinding = this.getTypeBinding(this.scope.getType(TypeConstants.JAVA_LANG_LONG, 3)); + } else if ("java.lang.Short".equals(name)) {//$NON-NLS-1$ + typeBinding = this.getTypeBinding(this.scope.getType(TypeConstants.JAVA_LANG_SHORT, 3)); + } else if ("java.lang.Void".equals(name)) {//$NON-NLS-1$ + typeBinding = this.getTypeBinding(this.scope.getType(TypeConstants.JAVA_LANG_VOID, 3)); + } + } catch (AbortCompilation e) { + // ignore missing types + } + if (typeBinding != null && !typeBinding.isRecovered()) { + return typeBinding; + } + return null; + } + + synchronized IAnnotationBinding resolveAnnotation(final Annotation domASTNode) { + Object oldNode = this.newAstToOldAst.get(domASTNode); + if (oldNode instanceof org.eclipse.jdt.internal.compiler.ast.Annotation) { + org.eclipse.jdt.internal.compiler.ast.Annotation internalAstNode = + (org.eclipse.jdt.internal.compiler.ast.Annotation) oldNode; + + IAnnotationBinding domAnnotation = getAnnotationInstance(internalAstNode.getCompilerAnnotation()); + if (domAnnotation == null) + return null; + this.bindingsToAstNodes.put(domAnnotation, domASTNode); + return domAnnotation; + } + return null; + } + + /* + * Method declared on BindingResolver. + */ + public CompilationUnitScope scope() { + return this.scope; + } + + /* + * Method declared on BindingResolver. + */ + synchronized void store(ASTNode node, org.eclipse.jdt.internal.compiler.ast.ASTNode oldASTNode) { + this.newAstToOldAst.put(node, oldASTNode); + } + + /* + * Method declared on BindingResolver. + */ + synchronized void updateKey(ASTNode node, ASTNode newNode) { + Object astNode = this.newAstToOldAst.remove(node); + if (astNode != null) { + this.newAstToOldAst.put(newNode, astNode); + } + } + + /** + * Answer an array type binding with the given type binding and the given + * dimensions. + * + * <p>If the given type binding is an array binding, then the resulting dimensions is the given dimensions + * plus the existing dimensions of the array binding. Otherwise the resulting dimensions is the given + * dimensions.</p> + * + * <p> + * The default implementation of this method returns <code>null</code>. + * Subclasses may reimplement. + * </p> + * + * @param typeBinding the given type binding + * @param dimensions the given dimensions + * @return an array type binding with the given type binding and the given + * dimensions + * @throws IllegalArgumentException if the type binding represents the <code>void</code> type binding + */ + ITypeBinding resolveArrayType(ITypeBinding typeBinding, int dimensions) { + if (typeBinding instanceof RecoveredTypeBinding) throw new IllegalArgumentException("Cannot be called on a recovered type binding"); //$NON-NLS-1$ + ITypeBinding leafComponentType = typeBinding; + int actualDimensions = dimensions; + if (typeBinding.isArray()) { + leafComponentType = typeBinding.getElementType(); + actualDimensions += typeBinding.getDimensions(); + } + org.eclipse.jdt.internal.compiler.lookup.TypeBinding leafTypeBinding = null; + if (leafComponentType.isPrimitive()) { + String name = leafComponentType.getBinaryName(); + switch(name.charAt(0)) { + case 'I' : + leafTypeBinding = org.eclipse.jdt.internal.compiler.lookup.TypeBinding.INT; + break; + case 'B' : + leafTypeBinding = org.eclipse.jdt.internal.compiler.lookup.TypeBinding.BYTE; + break; + case 'Z' : + leafTypeBinding = org.eclipse.jdt.internal.compiler.lookup.TypeBinding.BOOLEAN; + break; + case 'C' : + leafTypeBinding = org.eclipse.jdt.internal.compiler.lookup.TypeBinding.CHAR; + break; + case 'J' : + leafTypeBinding = org.eclipse.jdt.internal.compiler.lookup.TypeBinding.LONG; + break; + case 'S' : + leafTypeBinding = org.eclipse.jdt.internal.compiler.lookup.TypeBinding.SHORT; + break; + case 'D' : + leafTypeBinding = org.eclipse.jdt.internal.compiler.lookup.TypeBinding.DOUBLE; + break; + case 'F' : + leafTypeBinding = org.eclipse.jdt.internal.compiler.lookup.TypeBinding.FLOAT; + break; + case 'V' : + throw new IllegalArgumentException(); + } + } else { + if (!(leafComponentType instanceof TypeBinding)) return null; + leafTypeBinding = ((TypeBinding) leafComponentType).binding; + } + return this.getTypeBinding(lookupEnvironment().createArrayType(leafTypeBinding, actualDimensions)); + } + //{ObjectTeams: Binding for callin/callout mappings + @Override + synchronized IMethodMappingBinding getMethodMappingBinding(org.eclipse.objectteams.otdt.internal.core.compiler.lookup.CallinCalloutBinding callbinding) + { + if (callbinding == null) + { + return null; + } + + if (callbinding.isValidBinding()) + { + MethodMappingBinding binding = + (MethodMappingBinding)bindingTables.compilerBindingsToASTBindings.get(callbinding); + if (binding != null) + { + return binding; + } + else + { + binding = new MethodMappingBinding(this, callbinding); + bindingTables.compilerBindingsToASTBindings.put(callbinding, binding); + return binding; + } + } + + return null; + } +//mkr} + +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultCommentMapper.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultCommentMapper.java new file mode 100644 index 000000000..0be0ff23b --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultCommentMapper.java @@ -0,0 +1,644 @@ +/******************************************************************************* + * Copyright (c) 2004, 2009 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.dom; + +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.core.compiler.InvalidInputException; +import org.eclipse.jdt.internal.compiler.parser.Scanner; +import org.eclipse.jdt.internal.compiler.parser.TerminalTokens; +import org.eclipse.jdt.internal.compiler.util.Util; + +/** + * Internal class for associating comments with AST nodes. + * + * @since 3.0 + */ +class DefaultCommentMapper { + Comment[] comments; + Scanner scanner; + + // extended nodes storage + int leadingPtr; + ASTNode[] leadingNodes; + long[] leadingIndexes; + int trailingPtr, lastTrailingPtr; + ASTNode[] trailingNodes; + long[] trailingIndexes; + static final int STORAGE_INCREMENT = 16; + + /** + * @param table the given table of comments + */ + DefaultCommentMapper(Comment[] table) { + this.comments = table; + } + + boolean hasSameTable(Comment[] table) { + return this.comments == table; + } + + /** + * Get comment of the list which includes a given position + * + * @param position The position belonging to the looked up comment + * @return comment which includes the given position or null if none was found + */ + Comment getComment(int position) { + + if (this.comments == null) { + return null; + } + int size = this.comments.length; + if (size == 0) { + return null; + } + int index = getCommentIndex(0, position, 0); + if (index<0) { + return null; + } + return this.comments[index]; + } + + /* + * Get the index of comment which contains given position. + * If there's no matching comment, then return depends on exact parameter: + * = 0: return -1 + * < 0: return index of the comment before the given position + * > 0: return index of the comment after the given position + */ + private int getCommentIndex(int start, int position, int exact) { + if (position == 0) { + if (this.comments.length > 0 && this.comments[0].getStartPosition() == 0) { + return 0; + } + return -1; + } + int bottom = start, top = this.comments.length - 1; + int i = 0, index = -1; + Comment comment = null; + while (bottom <= top) { + i = bottom + (top - bottom) /2; + comment = this.comments[i]; + int commentStart = comment.getStartPosition(); + if (position < commentStart) { + top = i-1; + } else if (position >=(commentStart+comment.getLength())) { + bottom = i+1; + } else { + index = i; + break; + } + } + if (index<0 && exact!=0) { + comment = this.comments[i]; + if (position < comment.getStartPosition()) { + return exact<0 ? i-1 : i; + } else { + return exact<0 ? i : i+1; + } + } + return index; + } + + /** + * Returns the extended start position of the given node. Unlike + * {@link ASTNode#getStartPosition()} and {@link ASTNode#getLength()}, + * the extended source range may include comments and whitespace + * immediately before or after the normal source range for the node. + * + * @param node the node + * @return the 0-based character index, or <code>-1</code> + * if no source position information is recorded for this node + * @see #getExtendedLength(ASTNode) + * @since 3.0 + */ + public int getExtendedStartPosition(ASTNode node) { + if (this.leadingPtr >= 0) { + long range = -1; + for (int i=0; range<0 && i<=this.leadingPtr; i++) { + if (this.leadingNodes[i] == node) range = this.leadingIndexes[i]; + } + if (range >= 0) { + return this.comments[(int)(range>>32)].getStartPosition() ; + } + } + return node.getStartPosition(); + } + + /* + * Search the line number corresponding to a specific position + * between the given line range (inclusive) + * @param position int + * @parem lineRange size-2 int[] + * @return int + */ + public final int getLineNumber(int position, int[] lineRange) { + int[] lineEnds = this.scanner.lineEnds; + int length = lineEnds.length; + return Util.getLineNumber(position, lineEnds, (lineRange[0] > length ? length : lineRange[0]) -1, (lineRange[1] > length ? length : lineRange[1]) - 1); + } + + /* + * Returns the extended end position of the given node. + */ + public int getExtendedEnd(ASTNode node) { + int end = node.getStartPosition() + node.getLength(); + if (this.trailingPtr >= 0) { + long range = -1; + for (int i=0; range<0 && i<=this.trailingPtr; i++) { + if (this.trailingNodes[i] == node) range = this.trailingIndexes[i]; + } + if (range >= 0) { + Comment lastComment = this.comments[(int) range]; + end = lastComment.getStartPosition() + lastComment.getLength(); + } + } + return end-1; + } + + /** + * Returns the extended source length of the given node. Unlike + * {@link ASTNode#getStartPosition()} and {@link ASTNode#getLength()}, + * the extended source range may include comments and whitespace + * immediately before or after the normal source range for the node. + * + * @param node the node + * @return a (possibly 0) length, or <code>0</code> + * if no source position information is recorded for this node + * @see #getExtendedStartPosition(ASTNode) + * @see #getExtendedEnd(ASTNode) + * @since 3.0 + */ + public int getExtendedLength(ASTNode node) { + return getExtendedEnd(node) - getExtendedStartPosition(node) + 1; + } + + /** + * Return index of first leading comment of a given node. + * + * @param node + * @return index of first leading comment or -1 if node has no leading comment + */ + int firstLeadingCommentIndex(ASTNode node) { + if (this.leadingPtr >= 0) { + for (int i=0; i<=this.leadingPtr; i++) { + if (this.leadingNodes[i] == node) { + return (int) (this.leadingIndexes[i]>>32); + } + } + } + return -1; + } + + /** + * Return index of last trailing comment of a given node. + * + * @param node + * @return index of last trailing comment or -1 if node has no trailing comment + */ + int lastTrailingCommentIndex(ASTNode node) { + if (this.trailingPtr >= 0) { + for (int i=0; i<=this.trailingPtr; i++) { + if (this.trailingNodes[i] == node) { + return (int) this.trailingIndexes[i]; + } + } + } + return -1; + } + + /* + * Initialize leading and trailing comments tables in whole nodes hierarchy of a compilation + * unit. + * Scanner is necessary to scan between nodes and comments and verify if there's + * nothing else than white spaces. + */ + void initialize(CompilationUnit unit, Scanner sc) { + + // Init array pointers + this.leadingPtr = -1; + this.trailingPtr = -1; + + // Init comments + this.comments = unit.optionalCommentTable; + if (this.comments == null) { + return; + } + int size = this.comments.length; + if (size == 0) { + return; + } + + // Init scanner and start ranges computing + this.scanner = sc; + this.scanner.tokenizeWhiteSpace = true; + + // Start unit visit + DefaultASTVisitor commentVisitor = new CommentMapperVisitor(); + unit.accept(commentVisitor); + + // Reduce leading arrays if necessary + int leadingCount = this.leadingPtr + 1; + if (leadingCount > 0 && leadingCount < this.leadingIndexes.length) { + System.arraycopy(this.leadingNodes, 0, this.leadingNodes = new ASTNode[leadingCount], 0, leadingCount); + System.arraycopy(this.leadingIndexes, 0, this.leadingIndexes= new long[leadingCount], 0, leadingCount); + } + + // Reduce trailing arrays if necessary + if (this.trailingPtr >= 0) { + // remove last remaining unresolved nodes + while (this.trailingIndexes[this.trailingPtr] == -1) { + this.trailingPtr--; + if (this.trailingPtr < 0) { + this.trailingIndexes = null; + this.trailingNodes = null; + break; + } + } + + // reduce array size + int trailingCount = this.trailingPtr + 1; + if (trailingCount > 0 && trailingCount < this.trailingIndexes.length) { + System.arraycopy(this.trailingNodes, 0, this.trailingNodes = new ASTNode[trailingCount], 0, trailingCount); + System.arraycopy(this.trailingIndexes, 0, this.trailingIndexes= new long[trailingCount], 0, trailingCount); + } + } + + // Release scanner as it's only used during unit visit + this.scanner = null; + } + + /** + * Search and store node leading comments. Comments are searched in position range + * from previous extended position to node start position. If one or several comment are found, + * returns first comment start position, otherwise returns node start position. + * <p> + * Starts to search for first comment before node start position and return if none was found... + *</p><p> + * When first comment is found before node, goes up in comment list until one of + * following conditions becomes true: + * <ol> + * <li>comment end is before previous end</li> + * <li>comment start and previous end is on the same line but not on same line of node start</li> + * <li>there's other than white characters between current node and comment</li> + * <li>there's more than 1 line between current node and comment</li> + * </ol> + * If some comment have been found, then no token should be on + * on the same line before, so remove all comments which do not verify this assumption. + * </p><p> + * If finally there's leading still comments, then stores indexes of the first and last one + * in leading comments table. + */ + int storeLeadingComments(ASTNode node, int previousEnd, int[] parentLineRange) { + // Init extended position + int nodeStart = node.getStartPosition(); + int extended = nodeStart; + + // Get line of node start position + int previousEndLine = getLineNumber(previousEnd, parentLineRange); + int nodeStartLine = getLineNumber(nodeStart, parentLineRange); + + // Find first comment index + int idx = getCommentIndex(0, nodeStart, -1); + if (idx == -1) { + return nodeStart; + } + + // Look after potential comments + int startIdx = -1; + int endIdx = idx; + int previousStart = nodeStart; + while (idx >= 0 && previousStart >= previousEnd) { + // Verify for each comment that there's only white spaces between end and start of {following comment|node} + Comment comment = this.comments[idx]; + int commentStart = comment.getStartPosition(); + int end = commentStart+comment.getLength()-1; + int commentLine = getLineNumber(commentStart, parentLineRange); + if (end <= previousEnd || (commentLine == previousEndLine && commentLine != nodeStartLine)) { + // stop search on condition 1) and 2) + break; + } else if ((end+1) < previousStart) { // may be equals => then no scan is necessary + this.scanner.resetTo(end+1, previousStart); + try { + int token = this.scanner.getNextToken(); + if (token != TerminalTokens.TokenNameWHITESPACE || this.scanner.currentPosition != previousStart) { + // stop search on condition 3) + // if first comment fails, then there's no extended position in fact + if (idx == endIdx) { + return nodeStart; + } + break; + } + } catch (InvalidInputException e) { + // Should not happen, but return no extended position... + return nodeStart; + } + // verify that there's no more than one line between node/comments + char[] gap = this.scanner.getCurrentIdentifierSource(); + int nbrLine = 0; + int pos = -1; + while ((pos=CharOperation.indexOf('\n', gap,pos+1)) >= 0) { + nbrLine++; + } + if (nbrLine > 1) { + // stop search on condition 4) + break; + } + } + // Store previous infos + previousStart = commentStart; + startIdx = idx--; + } + if (startIdx != -1) { + // Verify that there's no token on the same line before first leading comment + int commentStart = this.comments[startIdx].getStartPosition(); + if (previousEnd < commentStart && previousEndLine != nodeStartLine) { + int lastTokenEnd = previousEnd; + this.scanner.resetTo(previousEnd, commentStart); + try { + while (this.scanner.currentPosition < commentStart) { + if (this.scanner.getNextToken() != TerminalTokens.TokenNameWHITESPACE) { + lastTokenEnd = this.scanner.getCurrentTokenEndPosition(); + } + } + } catch (InvalidInputException e) { + // do nothing + } + int lastTokenLine = getLineNumber(lastTokenEnd, parentLineRange); + int length = this.comments.length; + while (startIdx<length && lastTokenLine == getLineNumber(this.comments[startIdx].getStartPosition(), parentLineRange) && nodeStartLine != lastTokenLine) { + startIdx++; + } + } + // Store leading comments indexes + if (startIdx <= endIdx) { + if (++this.leadingPtr == 0) { + this.leadingNodes = new ASTNode[STORAGE_INCREMENT]; + this.leadingIndexes = new long[STORAGE_INCREMENT]; + } else if (this.leadingPtr == this.leadingNodes.length) { + int newLength = (this.leadingPtr*3/2)+STORAGE_INCREMENT; + System.arraycopy(this.leadingNodes, 0, this.leadingNodes = new ASTNode[newLength], 0, this.leadingPtr); + System.arraycopy(this.leadingIndexes, 0, this.leadingIndexes = new long[newLength], 0, this.leadingPtr); + } + this.leadingNodes[this.leadingPtr] = node; + this.leadingIndexes[this.leadingPtr] = (((long)startIdx)<<32) + endIdx; + extended = this.comments[endIdx].getStartPosition(); + } + } + return extended; + } + + /** + * Search and store node trailing comments. Comments are searched in position range + * from node end position to specified next start. If one or several comment are found, + * returns last comment end position, otherwise returns node end position. + * <p> + * Starts to search for first comment after node end position and return if none was found... + *</p><p> + * When first comment is found after node, goes down in comment list until one of + * following conditions becomes true: + * <ol> + * <li>comment start is after next start</li> + * <li>there's other than white characters between current node and comment</li> + * <li>there's more than 1 line between current node and comment</li> + *</ol> + * If at least potential comments have been found, then all of them has to be separated + * from following node. So, remove all comments which do not verify this assumption. + * Note that this verification is not applicable on last node. + * </p><p> + * If finally there's still trailing comments, then stores indexes of the first and last one + * in trailing comments table. + */ + int storeTrailingComments(ASTNode node, int nextStart, boolean lastChild, int[] parentLineRange) { + + // Init extended position + int nodeEnd = node.getStartPosition()+node.getLength()-1; + if (nodeEnd == nextStart) { + // special case for last child of its parent + if (++this.trailingPtr == 0) { + this.trailingNodes = new ASTNode[STORAGE_INCREMENT]; + this.trailingIndexes = new long[STORAGE_INCREMENT]; + this.lastTrailingPtr = -1; + } else if (this.trailingPtr == this.trailingNodes.length) { + int newLength = (this.trailingPtr*3/2)+STORAGE_INCREMENT; + System.arraycopy(this.trailingNodes, 0, this.trailingNodes = new ASTNode[newLength], 0, this.trailingPtr); + System.arraycopy(this.trailingIndexes, 0, this.trailingIndexes = new long[newLength], 0, this.trailingPtr); + } + this.trailingNodes[this.trailingPtr] = node; + this.trailingIndexes[this.trailingPtr] = -1; + return nodeEnd; + } + int extended = nodeEnd; + + // Get line number + int nodeEndLine = getLineNumber(nodeEnd, parentLineRange); + + // Find comments range index + int idx = getCommentIndex(0, nodeEnd, 1); + if (idx == -1) { + return nodeEnd; + } + + // Look after potential comments + int startIdx = idx; + int endIdx = -1; + int length = this.comments.length; + int commentStart = extended+1; + int previousEnd = nodeEnd+1; + int sameLineIdx = -1; + while (idx<length && commentStart < nextStart) { + // get comment and leave if next starting position has been reached + Comment comment = this.comments[idx]; + commentStart = comment.getStartPosition(); + // verify that there's nothing else than white spaces between node/comments + if (commentStart >= nextStart) { + // stop search on condition 1) + break; + } else if (previousEnd < commentStart) { + this.scanner.resetTo(previousEnd, commentStart); + try { + int token = this.scanner.getNextToken(); + if (token != TerminalTokens.TokenNameWHITESPACE || this.scanner.currentPosition != commentStart) { + // stop search on condition 2) + // if first index fails, then there's no extended position in fact... + if (idx == startIdx) { + return nodeEnd; + } + // otherwise we get the last index of trailing comment => break + break; + } + } catch (InvalidInputException e) { + // Should not happen, but return no extended position... + return nodeEnd; + } + // verify that there's no more than one line between node/comments + char[] gap = this.scanner.getCurrentIdentifierSource(); + int nbrLine = 0; + int pos = -1; + while ((pos=CharOperation.indexOf('\n', gap,pos+1)) >= 0) { + nbrLine++; + } + if (nbrLine > 1) { + // stop search on condition 3) + break; + } + } + // Store index if we're on the same line than node end + int commentLine = getLineNumber(commentStart, parentLineRange); + if (commentLine == nodeEndLine) { + sameLineIdx = idx; + } + // Store previous infos + previousEnd = commentStart+comment.getLength(); + endIdx = idx++; + } + if (endIdx != -1) { + // Verify that following node start is separated + if (!lastChild) { + int nextLine = getLineNumber(nextStart, parentLineRange); + int previousLine = getLineNumber(previousEnd, parentLineRange); + if((nextLine - previousLine) <= 1) { + if (sameLineIdx == -1) return nodeEnd; + endIdx = sameLineIdx; + } + } + // Store trailing comments indexes + if (++this.trailingPtr == 0) { + this.trailingNodes = new ASTNode[STORAGE_INCREMENT]; + this.trailingIndexes = new long[STORAGE_INCREMENT]; + this.lastTrailingPtr = -1; + } else if (this.trailingPtr == this.trailingNodes.length) { + int newLength = (this.trailingPtr*3/2)+STORAGE_INCREMENT; + System.arraycopy(this.trailingNodes, 0, this.trailingNodes = new ASTNode[newLength], 0, this.trailingPtr); + System.arraycopy(this.trailingIndexes, 0, this.trailingIndexes = new long[newLength], 0, this.trailingPtr); + } + this.trailingNodes[this.trailingPtr] = node; + long nodeRange = (((long)startIdx)<<32) + endIdx; + this.trailingIndexes[this.trailingPtr] = nodeRange; + // Compute new extended end + extended = this.comments[endIdx].getStartPosition()+this.comments[endIdx].getLength()-1; + // Look for children unresolved extended end + ASTNode previousNode = node; + int ptr = this.trailingPtr - 1; // children extended end were stored before + while (ptr >= 0) { + long range = this.trailingIndexes[ptr]; + if (range != -1) break; // there's no more unresolved nodes + ASTNode unresolved = this.trailingNodes[ptr]; + if (previousNode != unresolved.getParent()) break; // we're no longer in node ancestor hierarchy + this.trailingIndexes[ptr] = nodeRange; + previousNode = unresolved; + ptr--; // get previous node + } + // Remove remaining unresolved nodes + if (ptr > this.lastTrailingPtr) { + int offset = ptr - this.lastTrailingPtr; + for (int i=ptr+1; i<=this.trailingPtr; i++) { + this.trailingNodes[i-offset] = this.trailingNodes[i]; + this.trailingIndexes[i-offset] = this.trailingIndexes[i]; + } + this.trailingPtr -= offset; + } + this.lastTrailingPtr = this.trailingPtr; + } + return extended; + } + + class CommentMapperVisitor extends DefaultASTVisitor { + + ASTNode topSiblingParent = null; + ASTNode[] siblings = new ASTNode[10]; + int[][] parentLineRange = new int[10][]; + int siblingPtr = -1; + + protected boolean visitNode(ASTNode node) { + + // Get default previous end + ASTNode parent = node.getParent(); + int previousEnd = parent.getStartPosition(); + + // Look for sibling node + ASTNode sibling = parent == this.topSiblingParent ? (ASTNode) this.siblings[this.siblingPtr] : null; + if (sibling != null) { + // Found one previous sibling, so compute its trailing comments using current node start position + try { + previousEnd = storeTrailingComments(sibling, node.getStartPosition(), false, this.parentLineRange[this.siblingPtr]); + } catch (Exception ex) { + // Give up extended ranges at this level if unexpected exception happens... + } + } + + // Stop visit for malformed node (see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=84049) + if ((node.typeAndFlags & ASTNode.MALFORMED) != 0) { + return false; + } + + // Compute leading comments for current node + int[] previousLineRange = this.siblingPtr > -1 ? this.parentLineRange[this.siblingPtr] : new int[] {1, DefaultCommentMapper.this.scanner.linePtr+1}; + try { + storeLeadingComments(node, previousEnd, previousLineRange); + } catch (Exception ex) { + // Give up extended ranges at this level if unexpected exception happens... + } + + // Store current node as waiting sibling for its parent + if (this.topSiblingParent != parent) { + if (this.siblings.length == ++this.siblingPtr) { + System.arraycopy(this.siblings, 0, this.siblings = new ASTNode[this.siblingPtr*2], 0, this.siblingPtr); + System.arraycopy(this.parentLineRange, 0, this.parentLineRange = new int[this.siblingPtr*2][], 0, this.siblingPtr); + } + if (this.topSiblingParent == null) { + // node is a CompilationUnit + this.parentLineRange[this.siblingPtr] = previousLineRange; + } else { + int parentStart = parent.getStartPosition(); + int firstLine = getLineNumber(parentStart, previousLineRange); + int lastLine = getLineNumber(parentStart + parent.getLength() - 1, previousLineRange); + if (this.parentLineRange[this.siblingPtr] == null) { + this.parentLineRange[this.siblingPtr] = new int[] {firstLine, lastLine}; + } else { + int[] lineRange = this.parentLineRange[this.siblingPtr]; + lineRange[0] = firstLine; + lineRange[1] = lastLine; + } + } + this.topSiblingParent = parent; + } + this.siblings[this.siblingPtr] = node; + + // We're always ok to visit sub-levels + return true; + } + + protected void endVisitNode(ASTNode node) { + + // Look if a child node is waiting for trailing comments computing + ASTNode sibling = this.topSiblingParent == node ? (ASTNode) this.siblings[this.siblingPtr] : null; + if (sibling != null) { + try { + storeTrailingComments(sibling, node.getStartPosition()+node.getLength()-1, true, this.parentLineRange[this.siblingPtr]); + } catch (Exception ex) { + // Give up extended ranges at this level if unexpected exception happens... + } + } + // Remove sibling if needed + if (this.topSiblingParent != null /*not a CompilationUnit*/ + && this.topSiblingParent == node) { + this.siblingPtr--; + this.topSiblingParent = node.getParent(); + } + } + + public boolean visit ( CompilationUnit node) { + // do nothing special, just go down in sub-levels + return true; + } + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultValuePairBinding.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultValuePairBinding.java new file mode 100644 index 000000000..d51772cba --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultValuePairBinding.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2005, 2007 BEA Systems, Inc. + * 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: + * tyeung@bea.com - initial API and implementation + * IBM Corporation - implemented methods from IBinding + * IBM Corporation - renamed from ResolvedDefaultValuePair to DefaultValuePairBinding + *******************************************************************************/ +package org.eclipse.jdt.core.dom; + +import org.eclipse.jdt.core.dom.BindingResolver; +import org.eclipse.jdt.core.dom.IMethodBinding; + +/** + * Member value pair which compose of default values. + */ +class DefaultValuePairBinding extends MemberValuePairBinding { + + private org.eclipse.jdt.internal.compiler.lookup.MethodBinding method; + + DefaultValuePairBinding(org.eclipse.jdt.internal.compiler.lookup.MethodBinding binding, BindingResolver resolver) { + super(null, resolver); + this.method = binding; + this.value = MemberValuePairBinding.buildDOMValue(binding.getDefaultValue(), resolver); + } + + public IMethodBinding getMethodBinding() { + return this.bindingResolver.getMethodBinding(this.method); + } + + public String getName() { + return new String(this.method.selector); + } + + public Object getValue() { + return this.value; + } + + public boolean isDefault() { + return true; + } + + public boolean isDeprecated() { + return this.method.isDeprecated(); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DoStatement.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DoStatement.java new file mode 100644 index 000000000..41204909c --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DoStatement.java @@ -0,0 +1,274 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Do statement AST node type. + * + * <pre> + * DoStatement: + * <b>do</b> Statement <b>while</b> <b>(</b> Expression <b>)</b> <b>;</b> + * </pre> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class DoStatement extends Statement { + + /** + * The "expression" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor EXPRESSION_PROPERTY = + new ChildPropertyDescriptor(DoStatement.class, "expression", Expression.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "body" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor BODY_PROPERTY = + new ChildPropertyDescriptor(DoStatement.class, "body", Statement.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List properyList = new ArrayList(3); + createPropertyList(DoStatement.class, properyList); + addProperty(EXPRESSION_PROPERTY, properyList); + addProperty(BODY_PROPERTY, properyList); + PROPERTY_DESCRIPTORS = reapPropertyList(properyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The expression; lazily initialized; defaults to an unspecified, but + * legal, expression. + */ + private Expression expression = null; + + /** + * The body statement; lazily initialized; defaults to an empty block. + */ + private Statement body = null; + + /** + * Creates a new unparented do statement node owned by the given + * AST. By default, the expresssion is unspecified, but legal, + * and the body statement is an empty block. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + DoStatement(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == EXPRESSION_PROPERTY) { + if (get) { + return getExpression(); + } else { + setExpression((Expression) child); + return null; + } + } + if (property == BODY_PROPERTY) { + if (get) { + return getBody(); + } else { + setBody((Statement) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return DO_STATEMENT; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + DoStatement result = new DoStatement(target); + result.setSourceRange(getStartPosition(), getLength()); + result.copyLeadingComment(this); + result.setExpression((Expression) getExpression().clone(target)); + result.setBody((Statement) getBody().clone(target)); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + acceptChild(visitor, getBody()); + acceptChild(visitor, getExpression()); + } + visitor.endVisit(this); + } + + /** + * Returns the expression of this do statement. + * + * @return the expression node + */ + public Expression getExpression() { + if (this.expression == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.expression == null) { + preLazyInit(); + this.expression = new SimpleName(this.ast); + postLazyInit(this.expression, EXPRESSION_PROPERTY); + } + } + } + return this.expression; + } + + /** + * Sets the expression of this do statement. + * + * @param expression the expression node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setExpression(Expression expression) { + if (expression == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.expression; + preReplaceChild(oldChild, expression, EXPRESSION_PROPERTY); + this.expression = expression; + postReplaceChild(oldChild, expression, EXPRESSION_PROPERTY); + } + + /** + * Returns the body of this do statement. + * + * @return the body statement node + */ + public Statement getBody() { + if (this.body == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.body == null) { + preLazyInit(); + this.body = new Block(this.ast); + postLazyInit(this.body, BODY_PROPERTY); + } + } + } + return this.body; + } + + /** + * Sets the body of this do statement. + * <p> + * Special note: The Java language does not allow a local variable declaration + * to appear as the body of a do statement (they may only appear within a + * block). However, the AST will allow a <code>VariableDeclarationStatement</code> + * as the body of a <code>DoStatement</code>. To get something that will + * compile, be sure to embed the <code>VariableDeclarationStatement</code> + * inside a <code>Block</code>. + * </p> + * + * @param statement the body statement node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setBody(Statement statement) { + if (statement == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.body; + preReplaceChild(oldChild, statement, BODY_PROPERTY); + this.body = statement; + postReplaceChild(oldChild, statement, BODY_PROPERTY); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return super.memSize() + 2 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.expression == null ? 0 : getExpression().treeSize()) + + (this.body == null ? 0 : getBody().treeSize()); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DocCommentParser.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DocCommentParser.java new file mode 100644 index 000000000..037b4728c --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DocCommentParser.java @@ -0,0 +1,740 @@ +/******************************************************************************* + * Copyright (c) 2004, 2009 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.dom; + +import java.util.Iterator; +import java.util.List; + +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.core.compiler.InvalidInputException; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser; +import org.eclipse.jdt.internal.compiler.parser.Scanner; +import org.eclipse.jdt.internal.compiler.parser.ScannerHelper; +import org.eclipse.jdt.internal.compiler.parser.TerminalTokens; + +/** + * Internal parser used for decoding doc comments. + * + * @since 3.0 + */ +class DocCommentParser extends AbstractCommentParser { + + private Javadoc docComment; + private AST ast; + + DocCommentParser(AST ast, Scanner scanner, boolean check) { + super(null); + this.ast = ast; + this.scanner = scanner; + this.sourceLevel = this.ast.apiLevel() >= AST.JLS3 ? ClassFileConstants.JDK1_5 : ClassFileConstants.JDK1_3; + this.checkDocComment = check; + this.kind = DOM_PARSER | TEXT_PARSE; + } + + /* (non-Javadoc) + * Returns true if tag @deprecated is present in annotation. + * + * If annotation checking is enabled, will also construct an Annotation node, which will be stored into Parser.annotation + * slot for being consumed later on. + */ + public Javadoc parse(int[] positions) { + return parse(positions[0], positions[1]-positions[0]); + } + public Javadoc parse(int start, int length) { + + // Init + this.source = this.scanner.source; + this.lineEnds = this.scanner.lineEnds; + this.docComment = new Javadoc(this.ast); + + // Parse + if (this.checkDocComment) { + this.javadocStart = start; + this.javadocEnd = start+length-1; + this.firstTagPosition = this.javadocStart; + commentParse(); + } + this.docComment.setSourceRange(start, length); + if (this.ast.apiLevel == AST.JLS2_INTERNAL) { + setComment(start, length); // backward compatibility + } + return this.docComment; + } + + /** + * Sets the comment starting at the given position and with the given length. + * <p> + * Note the only purpose of this method is to hide deprecated warnings. + * @deprecated mark deprecated to hide deprecated usage + */ + private void setComment(int start, int length) { + this.docComment.setComment(new String(this.source, start, length)); + } + + public String toString() { + StringBuffer buffer = new StringBuffer(); + buffer.append("javadoc: ").append(this.docComment).append("\n"); //$NON-NLS-1$ //$NON-NLS-2$ + buffer.append(super.toString()); + return buffer.toString(); + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#createArgumentReference(char[], java.lang.Object, int) + */ + protected Object createArgumentReference(char[] name, int dim, boolean isVarargs, Object typeRef, long[] dimPositions, long argNamePos) throws InvalidInputException { + try { + MethodRefParameter argument = this.ast.newMethodRefParameter(); + ASTNode node = (ASTNode) typeRef; + int argStart = node.getStartPosition(); + int argEnd = node.getStartPosition()+node.getLength()-1; + if (dim > 0) argEnd = (int) dimPositions[dim-1]; + if (argNamePos >= 0) argEnd = (int) argNamePos; + if (name.length != 0) { + final SimpleName argName = new SimpleName(this.ast); + argName.internalSetIdentifier(new String(name)); + argument.setName(argName); + int argNameStart = (int) (argNamePos >>> 32); + argName.setSourceRange(argNameStart, argEnd-argNameStart+1); + } + Type argType = null; + if (node.getNodeType() == ASTNode.PRIMITIVE_TYPE) { + argType = (PrimitiveType) node; +// if (dim > 0) { +// argType = this.ast.newArrayType(argType, dim); +// argType.setSourceRange(argStart, ((int) dimPositions[dim-1])-argStart+1); +// } + } else { + Name argTypeName = (Name) node; + argType = this.ast.newSimpleType(argTypeName); + argType.setSourceRange(argStart, node.getLength()); + } + if (dim > 0 && !isVarargs) { + for (int i=0; i<dim; i++) { + argType = this.ast.newArrayType(argType); + argType.setSourceRange(argStart, ((int) dimPositions[i])-argStart+1); + } + } + argument.setType(argType); + argument.setSourceRange(argStart, argEnd - argStart + 1); + return argument; + } + catch (ClassCastException ex) { + throw new InvalidInputException(); + } + } +/* (non-Javadoc) + * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#createFieldReference() + */ + protected Object createFieldReference(Object receiver) throws InvalidInputException { + try { + MemberRef fieldRef = this.ast.newMemberRef(); + SimpleName fieldName = new SimpleName(this.ast); + fieldName.internalSetIdentifier(new String(this.identifierStack[0])); + fieldRef.setName(fieldName); + int start = (int) (this.identifierPositionStack[0] >>> 32); + int end = (int) this.identifierPositionStack[0]; + fieldName.setSourceRange(start, end - start + 1); + if (receiver == null) { + start = this.memberStart; + fieldRef.setSourceRange(start, end - start + 1); + } else { + Name typeRef = (Name) receiver; + fieldRef.setQualifier(typeRef); + start = typeRef.getStartPosition(); + end = fieldName.getStartPosition()+fieldName.getLength()-1; + fieldRef.setSourceRange(start, end-start+1); + } + return fieldRef; + } + catch (ClassCastException ex) { + throw new InvalidInputException(); + } + } + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#createMethodReference(java.lang.Object[]) + */ + protected Object createMethodReference(Object receiver, List arguments) throws InvalidInputException { + try { + // Create method ref + MethodRef methodRef = this.ast.newMethodRef(); + SimpleName methodName = new SimpleName(this.ast); + int length = this.identifierLengthStack[0] - 1; // may be > 0 for member class constructor reference + methodName.internalSetIdentifier(new String(this.identifierStack[length])); + methodRef.setName(methodName); + int start = (int) (this.identifierPositionStack[length] >>> 32); + int end = (int) this.identifierPositionStack[length]; + methodName.setSourceRange(start, end - start + 1); + // Set qualifier + if (receiver == null) { + start = this.memberStart; + methodRef.setSourceRange(start, end - start + 1); + } else { + Name typeRef = (Name) receiver; + methodRef.setQualifier(typeRef); + start = typeRef.getStartPosition(); + } + // Add arguments + if (arguments != null) { + Iterator parameters = arguments.listIterator(); + while (parameters.hasNext()) { + MethodRefParameter param = (MethodRefParameter) parameters.next(); + methodRef.parameters().add(param); + } + } + methodRef.setSourceRange(start, this.scanner.getCurrentTokenEndPosition()-start+1); + return methodRef; + } + catch (ClassCastException ex) { + throw new InvalidInputException(); + } + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#createTag() + */ + protected void createTag() { + TagElement tagElement = this.ast.newTagElement(); + int position = this.scanner.currentPosition; + this.scanner.resetTo(this.tagSourceStart, this.tagSourceEnd); + StringBuffer tagName = new StringBuffer(); + int start = this.tagSourceStart; + this.scanner.getNextChar(); + while (this.scanner.currentPosition <= (this.tagSourceEnd+1)) { + tagName.append(this.scanner.currentCharacter); + this.scanner.getNextChar(); + } + tagElement.setTagName(tagName.toString()); + if (this.inlineTagStarted) { + start = this.inlineTagStart; + TagElement previousTag = null; + if (this.astPtr == -1) { + previousTag = this.ast.newTagElement(); + previousTag.setSourceRange(start, this.tagSourceEnd-start+1); + pushOnAstStack(previousTag, true); + } else { + previousTag = (TagElement) this.astStack[this.astPtr]; + } + int previousStart = previousTag.getStartPosition(); + previousTag.fragments().add(tagElement); + previousTag.setSourceRange(previousStart, this.tagSourceEnd-previousStart+1); + } else { + pushOnAstStack(tagElement, true); + } + tagElement.setSourceRange(start, this.tagSourceEnd-start+1); + this.scanner.resetTo(position, this.javadocEnd); + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#createTypeReference() + */ + protected Object createTypeReference(int primitiveToken) { + int size = this.identifierLengthStack[this.identifierLengthPtr]; + String[] identifiers = new String[size]; + int pos = this.identifierPtr - size + 1; + for (int i = 0; i < size; i++) { + identifiers[i] = new String(this.identifierStack[pos+i]); + } + ASTNode typeRef = null; + if (primitiveToken == -1) { + typeRef = this.ast.internalNewName(identifiers); + } else { + switch (primitiveToken) { + case TerminalTokens.TokenNamevoid : + typeRef = this.ast.newPrimitiveType(PrimitiveType.VOID); + break; + case TerminalTokens.TokenNameboolean : + typeRef = this.ast.newPrimitiveType(PrimitiveType.BOOLEAN); + break; + case TerminalTokens.TokenNamebyte : + typeRef = this.ast.newPrimitiveType(PrimitiveType.BYTE); + break; + case TerminalTokens.TokenNamechar : + typeRef = this.ast.newPrimitiveType(PrimitiveType.CHAR); + break; + case TerminalTokens.TokenNamedouble : + typeRef = this.ast.newPrimitiveType(PrimitiveType.DOUBLE); + break; + case TerminalTokens.TokenNamefloat : + typeRef = this.ast.newPrimitiveType(PrimitiveType.FLOAT); + break; + case TerminalTokens.TokenNameint : + typeRef = this.ast.newPrimitiveType(PrimitiveType.INT); + break; + case TerminalTokens.TokenNamelong : + typeRef = this.ast.newPrimitiveType(PrimitiveType.LONG); + break; + case TerminalTokens.TokenNameshort : + typeRef = this.ast.newPrimitiveType(PrimitiveType.SHORT); + break; + default: + // should not happen + return null; + } + } + // Update ref for whole name + int start = (int) (this.identifierPositionStack[pos] >>> 32); +// int end = (int) this.identifierPositionStack[this.identifierPtr]; +// typeRef.setSourceRange(start, end-start+1); + // Update references of each simple name + if (size > 1) { + Name name = (Name)typeRef; + int nameIndex = size; + for (int i=this.identifierPtr; i>pos; i--, nameIndex--) { + int s = (int) (this.identifierPositionStack[i] >>> 32); + int e = (int) this.identifierPositionStack[i]; + name.index = nameIndex; + SimpleName simpleName = ((QualifiedName)name).getName(); + simpleName.index = nameIndex; + simpleName.setSourceRange(s, e-s+1); + name.setSourceRange(start, e-start+1); + name = ((QualifiedName)name).getQualifier(); + } + int end = (int) this.identifierPositionStack[pos]; + name.setSourceRange(start, end-start+1); + name.index = nameIndex; + } else { + int end = (int) this.identifierPositionStack[pos]; + typeRef.setSourceRange(start, end-start+1); + } + return typeRef; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#parseIdentifierTag(boolean) + */ + protected boolean parseIdentifierTag(boolean report) { + if (super.parseIdentifierTag(report)) { + createTag(); + this.index = this.tagSourceEnd+1; + this.scanner.resetTo(this.index, this.javadocEnd); + return true; + } + return false; + } + + /* + * Parse @return tag declaration + */ + protected boolean parseReturn() { + createTag(); + return true; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#parseTag(int) + */ + protected boolean parseTag(int previousPosition) throws InvalidInputException { + + // Read tag name + int currentPosition = this.index; + int token = readTokenAndConsume(); + char[] tagName = CharOperation.NO_CHAR; + if (currentPosition == this.scanner.startPosition) { + this.tagSourceStart = this.scanner.getCurrentTokenStartPosition(); + this.tagSourceEnd = this.scanner.getCurrentTokenEndPosition(); + tagName = this.scanner.getCurrentIdentifierSource(); + } else { + this.tagSourceEnd = currentPosition-1; + } + + // Try to get tag name other than java identifier + // (see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=51660) + if (this.scanner.currentCharacter != ' ' && !ScannerHelper.isWhitespace(this.scanner.currentCharacter)) { + tagNameToken: while (token != TerminalTokens.TokenNameEOF && this.index < this.scanner.eofPosition) { + int length = tagName.length; + // !, ", #, %, &, ', -, :, <, >, * chars and spaces are not allowed in tag names + switch (this.scanner.currentCharacter) { + case '}': + case '*': // break for '*' as this is perhaps the end of comment (bug 65288) + case '!': + case '#': + case '%': + case '&': + case '\'': + case '"': + case ':': + case '<': + case '>': + break tagNameToken; + case '-': // allowed in tag names as this character is often used in doclets (bug 68087) + System.arraycopy(tagName, 0, tagName = new char[length+1], 0, length); + tagName[length] = this.scanner.currentCharacter; + break; + default: + if (this.scanner.currentCharacter == ' ' || ScannerHelper.isWhitespace(this.scanner.currentCharacter)) { + break tagNameToken; + } + token = readTokenAndConsume(); + char[] ident = this.scanner.getCurrentIdentifierSource(); + System.arraycopy(tagName, 0, tagName = new char[length+ident.length], 0, length); + System.arraycopy(ident, 0, tagName, length, ident.length); + break; + } + this.tagSourceEnd = this.scanner.getCurrentTokenEndPosition(); + this.scanner.getNextChar(); + this.index = this.scanner.currentPosition; + } + } + int length = tagName.length; + this.index = this.tagSourceEnd+1; + this.scanner.currentPosition = this.tagSourceEnd+1; + this.tagSourceStart = previousPosition; + + // tage name may be empty (see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=125903) + if (tagName.length == 0) { + return false; + } + + // Decide which parse to perform depending on tag name + this.tagValue = NO_TAG_VALUE; + boolean valid = true; + switch (token) { + case TerminalTokens.TokenNameIdentifier : + switch (tagName[0]) { + case 'c': + if (length == TAG_CATEGORY_LENGTH && CharOperation.equals(TAG_CATEGORY, tagName)) { + this.tagValue = TAG_CATEGORY_VALUE; + valid = parseIdentifierTag(false); // TODO (frederic) reconsider parameter value when @category will be significant in spec + } else { + this.tagValue = TAG_OTHERS_VALUE; + createTag(); + } + break; + case 'd': + if (length == TAG_DEPRECATED_LENGTH && CharOperation.equals(TAG_DEPRECATED, tagName)) { + this.deprecated = true; + this.tagValue = TAG_DEPRECATED_VALUE; + } else { + this.tagValue = TAG_OTHERS_VALUE; + } + createTag(); + break; + case 'i': + if (length == TAG_INHERITDOC_LENGTH && CharOperation.equals(TAG_INHERITDOC, tagName)) { + if (this.reportProblems) { + recordInheritedPosition((((long) this.tagSourceStart) << 32) + this.tagSourceEnd); + } + this.tagValue = TAG_INHERITDOC_VALUE; + } else { + this.tagValue = TAG_OTHERS_VALUE; + } + createTag(); + break; + case 'p': + if (length == TAG_PARAM_LENGTH && CharOperation.equals(TAG_PARAM, tagName)) { + this.tagValue = TAG_PARAM_VALUE; + valid = parseParam(); + } else { + this.tagValue = TAG_OTHERS_VALUE; + createTag(); + } + break; + case 'e': + if (length == TAG_EXCEPTION_LENGTH && CharOperation.equals(TAG_EXCEPTION, tagName)) { + this.tagValue = TAG_EXCEPTION_VALUE; + valid = parseThrows(); + } else { + this.tagValue = TAG_OTHERS_VALUE; + createTag(); + } + break; + case 's': + if (length == TAG_SEE_LENGTH && CharOperation.equals(TAG_SEE, tagName)) { + this.tagValue = TAG_SEE_VALUE; + if (this.inlineTagStarted) { + // bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=53290 + // Cannot have @see inside inline comment + valid = false; + } else { + valid = parseReference(); + } + } else { + this.tagValue = TAG_OTHERS_VALUE; + createTag(); + } + break; + case 'l': + if (length == TAG_LINK_LENGTH && CharOperation.equals(TAG_LINK, tagName)) { + this.tagValue = TAG_LINK_VALUE; + } else if (length == TAG_LINKPLAIN_LENGTH && CharOperation.equals(TAG_LINKPLAIN, tagName)) { + this.tagValue = TAG_LINKPLAIN_VALUE; + } + if (this.tagValue != NO_TAG_VALUE) { + if (this.inlineTagStarted) { + valid = parseReference(); + } else { + // bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=53290 + // Cannot have @link outside inline comment + valid = false; + } + } else { + this.tagValue = TAG_OTHERS_VALUE; + createTag(); + } + break; + case 'v': + if (this.sourceLevel >= ClassFileConstants.JDK1_5 && length == TAG_VALUE_LENGTH && CharOperation.equals(TAG_VALUE, tagName)) { + this.tagValue = TAG_VALUE_VALUE; + if (this.inlineTagStarted) { + valid = parseReference(); + } else { + valid = false; + } + } else { + this.tagValue = TAG_OTHERS_VALUE; + createTag(); + } + break; + default: + this.tagValue = TAG_OTHERS_VALUE; + createTag(); + } + break; + case TerminalTokens.TokenNamereturn : + this.tagValue = TAG_RETURN_VALUE; + valid = parseReturn(); + break; + case TerminalTokens.TokenNamethrows : + this.tagValue = TAG_THROWS_VALUE; + valid = parseThrows(); + break; + case TerminalTokens.TokenNameabstract: + case TerminalTokens.TokenNameassert: + case TerminalTokens.TokenNameboolean: + case TerminalTokens.TokenNamebreak: + case TerminalTokens.TokenNamebyte: + case TerminalTokens.TokenNamecase: + case TerminalTokens.TokenNamecatch: + case TerminalTokens.TokenNamechar: + case TerminalTokens.TokenNameclass: + case TerminalTokens.TokenNamecontinue: + case TerminalTokens.TokenNamedefault: + case TerminalTokens.TokenNamedo: + case TerminalTokens.TokenNamedouble: + case TerminalTokens.TokenNameelse: + case TerminalTokens.TokenNameextends: + case TerminalTokens.TokenNamefalse: + case TerminalTokens.TokenNamefinal: + case TerminalTokens.TokenNamefinally: + case TerminalTokens.TokenNamefloat: + case TerminalTokens.TokenNamefor: + case TerminalTokens.TokenNameif: + case TerminalTokens.TokenNameimplements: + case TerminalTokens.TokenNameimport: + case TerminalTokens.TokenNameinstanceof: + case TerminalTokens.TokenNameint: + case TerminalTokens.TokenNameinterface: + case TerminalTokens.TokenNamelong: + case TerminalTokens.TokenNamenative: + case TerminalTokens.TokenNamenew: + case TerminalTokens.TokenNamenull: + case TerminalTokens.TokenNamepackage: + case TerminalTokens.TokenNameprivate: + case TerminalTokens.TokenNameprotected: + case TerminalTokens.TokenNamepublic: + case TerminalTokens.TokenNameshort: + case TerminalTokens.TokenNamestatic: + case TerminalTokens.TokenNamestrictfp: + case TerminalTokens.TokenNamesuper: + case TerminalTokens.TokenNameswitch: + case TerminalTokens.TokenNamesynchronized: + case TerminalTokens.TokenNamethis: + case TerminalTokens.TokenNamethrow: + case TerminalTokens.TokenNametransient: + case TerminalTokens.TokenNametrue: + case TerminalTokens.TokenNametry: + case TerminalTokens.TokenNamevoid: + case TerminalTokens.TokenNamevolatile: + case TerminalTokens.TokenNamewhile: + case TerminalTokens.TokenNameenum : + case TerminalTokens.TokenNameconst : + case TerminalTokens.TokenNamegoto : + this.tagValue = TAG_OTHERS_VALUE; + createTag(); + break; + } + this.textStart = this.index; + return valid; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#pushParamName(java.lang.Object) + */ + protected boolean pushParamName(boolean isTypeParam) { + int idIndex = isTypeParam ? 1 : 0; + final SimpleName name = new SimpleName(this.ast); + name.internalSetIdentifier(new String(this.identifierStack[idIndex])); + int nameStart = (int) (this.identifierPositionStack[idIndex] >>> 32); + int nameEnd = (int) (this.identifierPositionStack[idIndex] & 0x00000000FFFFFFFFL); + name.setSourceRange(nameStart, nameEnd-nameStart+1); + TagElement paramTag = this.ast.newTagElement(); + paramTag.setTagName(TagElement.TAG_PARAM); + if (isTypeParam) { // specific storage for @param <E> (see bug 79809) + // '<' was stored in identifiers stack + TextElement text = this.ast.newTextElement(); + text.setText(new String(this.identifierStack[0])); + int txtStart = (int) (this.identifierPositionStack[0] >>> 32); + int txtEnd = (int) (this.identifierPositionStack[0] & 0x00000000FFFFFFFFL); + text.setSourceRange(txtStart, txtEnd-txtStart+1); + paramTag.fragments().add(text); + // add simple name + paramTag.fragments().add(name); + // '>' was stored in identifiers stack + text = this.ast.newTextElement(); + text.setText(new String(this.identifierStack[2])); + txtStart = (int) (this.identifierPositionStack[2] >>> 32); + txtEnd = (int) (this.identifierPositionStack[2] & 0x00000000FFFFFFFFL); + text.setSourceRange(txtStart, txtEnd-txtStart+1); + paramTag.fragments().add(text); + // set param tag source range + paramTag.setSourceRange(this.tagSourceStart, txtEnd-this.tagSourceStart+1); + } else { + paramTag.setSourceRange(this.tagSourceStart, nameEnd-this.tagSourceStart+1); + paramTag.fragments().add(name); + } + pushOnAstStack(paramTag, true); + return true; + } + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#pushSeeRef(java.lang.Object) + */ + protected boolean pushSeeRef(Object statement) { + TagElement seeTag = this.ast.newTagElement(); + ASTNode node = (ASTNode) statement; + seeTag.fragments().add(node); + int end = node.getStartPosition()+node.getLength()-1; + if (this.inlineTagStarted) { + seeTag.setSourceRange(this.inlineTagStart, end-this.inlineTagStart+1); + switch (this.tagValue) { + case TAG_LINK_VALUE: + seeTag.setTagName(TagElement.TAG_LINK); + break; + case TAG_LINKPLAIN_VALUE: + seeTag.setTagName(TagElement.TAG_LINKPLAIN); + break; + case TAG_VALUE_VALUE: + seeTag.setTagName(TagElement.TAG_VALUE); + break; + } + TagElement previousTag = null; + int previousStart = this.inlineTagStart; + if (this.astPtr == -1) { + previousTag = this.ast.newTagElement(); + pushOnAstStack(previousTag, true); + } else { + previousTag = (TagElement) this.astStack[this.astPtr]; + previousStart = previousTag.getStartPosition(); + } + previousTag.fragments().add(seeTag); + previousTag.setSourceRange(previousStart, end-previousStart+1); + } else { + seeTag.setTagName(TagElement.TAG_SEE); + seeTag.setSourceRange(this.tagSourceStart, end-this.tagSourceStart+1); + pushOnAstStack(seeTag, true); + } + return true; + } + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#pushText(int, int) + */ + protected void pushText(int start, int end) { + + // Create text element + TextElement text = this.ast.newTextElement(); + text.setText(new String( this.source, start, end-start)); + text.setSourceRange(start, end-start); + + // Search previous tag on which to add the text element + TagElement previousTag = null; + int previousStart = start; + if (this.astPtr == -1) { + previousTag = this.ast.newTagElement(); + previousTag.setSourceRange(start, end-start); + pushOnAstStack(previousTag, true); + } else { + previousTag = (TagElement) this.astStack[this.astPtr]; + previousStart = previousTag.getStartPosition(); + } + + // If we're in a inline tag, then retrieve previous tag in its fragments + List fragments = previousTag.fragments(); + if (this.inlineTagStarted) { + int size = fragments.size(); + if (size == 0) { + // no existing fragment => just add the element + TagElement inlineTag = this.ast.newTagElement(); + fragments.add(inlineTag); + previousTag = inlineTag; + } else { + // If last fragment is a tag, then use it as previous tag + ASTNode lastFragment = (ASTNode) fragments.get(size-1); + if (lastFragment.getNodeType() == ASTNode.TAG_ELEMENT) { + previousTag = (TagElement) lastFragment; + previousStart = previousTag.getStartPosition(); + } + } + } + + // Add the text + previousTag.fragments().add(text); + previousTag.setSourceRange(previousStart, end-previousStart); + this.textStart = -1; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#pushThrowName(java.lang.Object) + */ + protected boolean pushThrowName(Object typeRef) { + TagElement throwsTag = this.ast.newTagElement(); + switch (this.tagValue) { + case TAG_THROWS_VALUE: + throwsTag.setTagName(TagElement.TAG_THROWS); + break; + case TAG_EXCEPTION_VALUE: + throwsTag.setTagName(TagElement.TAG_EXCEPTION); + break; + } + throwsTag.setSourceRange(this.tagSourceStart, this.scanner.getCurrentTokenEndPosition()-this.tagSourceStart+1); + throwsTag.fragments().add(typeRef); + pushOnAstStack(throwsTag, true); + return true; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.compiler.parser.AbstractCommentParser#refreshInlineTagPosition(int) + */ + protected void refreshInlineTagPosition(int previousPosition) { + if (this.astPtr != -1) { + TagElement previousTag = (TagElement) this.astStack[this.astPtr]; + if (this.inlineTagStarted) { + int previousStart = previousTag.getStartPosition(); + previousTag.setSourceRange(previousStart, previousPosition-previousStart+1); + if (previousTag.fragments().size() > 0) { + ASTNode inlineTag = (ASTNode) previousTag.fragments().get(previousTag.fragments().size()-1); + if (inlineTag.getNodeType() == ASTNode.TAG_ELEMENT) { + int inlineStart = inlineTag.getStartPosition(); + inlineTag.setSourceRange(inlineStart, previousPosition-inlineStart+1); + } + } + } + } + } + + /* + * Add stored tag elements to associated comment. + */ + protected void updateDocComment() { + for (int idx = 0; idx <= this.astPtr; idx++) { + this.docComment.tags().add(this.astStack[idx]); + } + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/EmptyStatement.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/EmptyStatement.java new file mode 100644 index 000000000..da132085f --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/EmptyStatement.java @@ -0,0 +1,117 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Null statement AST node type. + * + * <pre> + * EmptyStatement: + * <b>;</b> + * </pre> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class EmptyStatement extends Statement { + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List properyList = new ArrayList(1); + createPropertyList(EmptyStatement.class, properyList); + PROPERTY_DESCRIPTORS = reapPropertyList(properyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * Creates a new unparented null statement node owned by the given AST. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + EmptyStatement(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return EMPTY_STATEMENT; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + EmptyStatement result = new EmptyStatement(target); + result.setSourceRange(getStartPosition(), getLength()); + result.copyLeadingComment(this); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + visitor.visit(this); + visitor.endVisit(this); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return memSize(); + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/EnhancedForStatement.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/EnhancedForStatement.java new file mode 100644 index 000000000..c01598219 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/EnhancedForStatement.java @@ -0,0 +1,329 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Enhanced For statement AST node type (added in JLS3 API). + * + * <pre> + * EnhancedForStatement: + * <b>for</b> <b>(</b> FormalParameter <b>:</b> Expression <b>)</b> + * Statement + * </pre> + * The FormalParameter is represented by a <code>SingleVariableDeclaration</code> + * (without an initializer). + * + * @since 3.1 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class EnhancedForStatement extends Statement { + + /** + * The "parameter" structural property of this node type. + */ + public static final ChildPropertyDescriptor PARAMETER_PROPERTY = + new ChildPropertyDescriptor(EnhancedForStatement.class, "parameter", SingleVariableDeclaration.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "expression" structural property of this node type. + */ + public static final ChildPropertyDescriptor EXPRESSION_PROPERTY = + new ChildPropertyDescriptor(EnhancedForStatement.class, "expression", Expression.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "body" structural property of this node type. + */ + public static final ChildPropertyDescriptor BODY_PROPERTY = + new ChildPropertyDescriptor(EnhancedForStatement.class, "body", Statement.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List properyList = new ArrayList(4); + createPropertyList(EnhancedForStatement.class, properyList); + addProperty(PARAMETER_PROPERTY, properyList); + addProperty(EXPRESSION_PROPERTY, properyList); + addProperty(BODY_PROPERTY, properyList); + PROPERTY_DESCRIPTORS = reapPropertyList(properyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The parameter; lazily initialized; defaults to a unspecified, + * legal node. + */ + private SingleVariableDeclaration parameter = null; + + /** + * The expression; lazily initialized; defaults to a unspecified, but legal, + * expression. + */ + private Expression expression = null; + + /** + * The body statement; lazily initialized; defaults to an empty block + * statement. + */ + private Statement body = null; + + /** + * Creates a new AST node for an enchanced for statement owned by the + * given AST. By default, the parameter and expression are unspecified + * but legal subtrees, and the body is an empty block. + * + * @param ast the AST that is to own this node + */ + EnhancedForStatement(AST ast) { + super(ast); + unsupportedIn2(); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == PARAMETER_PROPERTY) { + if (get) { + return getParameter(); + } else { + setParameter((SingleVariableDeclaration) child); + return null; + } + } + if (property == EXPRESSION_PROPERTY) { + if (get) { + return getExpression(); + } else { + setExpression((Expression) child); + return null; + } + } + if (property == BODY_PROPERTY) { + if (get) { + return getBody(); + } else { + setBody((Statement) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return ENHANCED_FOR_STATEMENT; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + EnhancedForStatement result = new EnhancedForStatement(target); + result.setSourceRange(getStartPosition(), getLength()); + result.copyLeadingComment(this); + result.setParameter((SingleVariableDeclaration) getParameter().clone(target)); + result.setExpression((Expression) getExpression().clone(target)); + result.setBody( + (Statement) ASTNode.copySubtree(target, getBody())); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + acceptChild(visitor, getParameter()); + acceptChild(visitor, getExpression()); + acceptChild(visitor, getBody()); + } + visitor.endVisit(this); + } + + /** + * Returns the formal parameter in this enhanced for statement. + * + * @return the parameter + */ + public SingleVariableDeclaration getParameter() { + if (this.parameter == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.parameter == null) { + preLazyInit(); + this.parameter = this.ast.newSingleVariableDeclaration(); + postLazyInit(this.parameter, PARAMETER_PROPERTY); + } + } + } + return this.parameter; + } + + /** + * Sets the formal parameter in this enhanced for statement. + * + * @param parameter the new parameter + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public void setParameter(SingleVariableDeclaration parameter) { + if (parameter == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.parameter; + preReplaceChild(oldChild, parameter, PARAMETER_PROPERTY); + this.parameter = parameter; + postReplaceChild(oldChild, parameter, PARAMETER_PROPERTY); + } + + /** + * Returns the expression of this enhanced for statement. + * + * @return the expression node + */ + public Expression getExpression() { + if (this.expression == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.expression == null) { + preLazyInit(); + this.expression = new SimpleName(this.ast); + postLazyInit(this.expression, EXPRESSION_PROPERTY); + } + } + } + return this.expression; + } + + /** + * Sets the expression of this enhanced for statement. + * + * @param expression the new expression node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setExpression(Expression expression) { + if (expression == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.expression; + preReplaceChild(oldChild, expression, EXPRESSION_PROPERTY); + this.expression = expression; + postReplaceChild(oldChild, expression, EXPRESSION_PROPERTY); + } + + /** + * Returns the body of this enchanced for statement. + * + * @return the body statement node + */ + public Statement getBody() { + if (this.body == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.body == null) { + preLazyInit(); + this.body = new Block(this.ast); + postLazyInit(this.body, BODY_PROPERTY); + } + } + } + return this.body; + } + + /** + * Sets the body of this enhanced for statement. + * + * @param statement the body statement node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setBody(Statement statement) { + if (statement == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.body; + preReplaceChild(oldChild, statement, BODY_PROPERTY); + this.body = statement; + postReplaceChild(oldChild, statement, BODY_PROPERTY); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return super.memSize() + 3 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.parameter == null ? 0 : getParameter().treeSize()) + + (this.expression == null ? 0 : getExpression().treeSize()) + + (this.body == null ? 0 : getBody().treeSize()); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/EnumConstantDeclaration.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/EnumConstantDeclaration.java new file mode 100644 index 000000000..cd194bbc9 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/EnumConstantDeclaration.java @@ -0,0 +1,390 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Enumeration constant declaration AST node type (added in JLS3 API). + * + * <pre> + * EnumConstantDeclaration: + * [ Javadoc ] { ExtendedModifier } Identifier + * [ <b>(</b> [ Expression { <b>,</b> Expression } ] <b>)</b> ] + * [ AnonymousClassDeclaration ] + * </pre> + * <p> + * When a Javadoc comment is present, the source + * range begins with the first character of the "/**" comment delimiter. + * When there is no Javadoc comment, the source range begins with the first + * character of the identifier. If there are class body declarations, the + * source range extends through the last character of the last character of + * the "}" token following the body declarations. If there are arguments but + * no class body declarations, the source range extends through the last + * character of the ")" token following the arguments. If there are no + * arguments and no class body declarations, the source range extends through + * the last character of the identifier. + * </p> + * + * @since 3.1 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class EnumConstantDeclaration extends BodyDeclaration { + + /** + * The "javadoc" structural property of this node type. + */ + public static final ChildPropertyDescriptor JAVADOC_PROPERTY = + internalJavadocPropertyFactory(EnumConstantDeclaration.class); + + /** + * The "modifiers" structural property of this node type). + */ + public static final ChildListPropertyDescriptor MODIFIERS2_PROPERTY = + internalModifiers2PropertyFactory(EnumConstantDeclaration.class); + + /** + * The "name" structural property of this node type. + */ + public static final ChildPropertyDescriptor NAME_PROPERTY = + new ChildPropertyDescriptor(EnumConstantDeclaration.class, "name", SimpleName.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "arguments" structural property of this node type. + */ + public static final ChildListPropertyDescriptor ARGUMENTS_PROPERTY = + new ChildListPropertyDescriptor(EnumConstantDeclaration.class, "arguments", Expression.class, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "anonymousClassDeclaration" structural property of this node type. + */ + public static final ChildPropertyDescriptor ANONYMOUS_CLASS_DECLARATION_PROPERTY = + new ChildPropertyDescriptor(EnumConstantDeclaration.class, "anonymousClassDeclaration", AnonymousClassDeclaration.class, OPTIONAL, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List properyList = new ArrayList(6); + createPropertyList(EnumConstantDeclaration.class, properyList); + addProperty(JAVADOC_PROPERTY, properyList); + addProperty(MODIFIERS2_PROPERTY, properyList); + addProperty(NAME_PROPERTY, properyList); + addProperty(ARGUMENTS_PROPERTY, properyList); + addProperty(ANONYMOUS_CLASS_DECLARATION_PROPERTY, properyList); + PROPERTY_DESCRIPTORS = reapPropertyList(properyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The constant name; lazily initialized; defaults to a unspecified, + * legal Java class identifier. + */ + private SimpleName constantName = null; + + /** + * The list of argument expressions (element type: + * <code>Expression</code>). Defaults to an empty list. + */ + private ASTNode.NodeList arguments = + new ASTNode.NodeList(ARGUMENTS_PROPERTY); + + /** + * The optional anonymous class declaration; <code>null</code> for none; + * defaults to none. + */ + private AnonymousClassDeclaration optionalAnonymousClassDeclaration = null; + + /** + * Creates a new AST node for an enumeration constants declaration owned by + * the given AST. By default, the enumeration constant has an unspecified, + * but legal, name; no javadoc; an empty list of modifiers and annotations; + * an empty list of arguments; and does not declare an anonymous class. + * <p> + * N.B. This constructor is package-private; all subclasses must be + * declared in the same package; clients are unable to declare + * additional subclasses. + * </p> + * + * @param ast the AST that is to own this node + */ + EnumConstantDeclaration(AST ast) { + super(ast); + unsupportedIn2(); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == JAVADOC_PROPERTY) { + if (get) { + return getJavadoc(); + } else { + setJavadoc((Javadoc) child); + return null; + } + } + if (property == NAME_PROPERTY) { + if (get) { + return getName(); + } else { + setName((SimpleName) child); + return null; + } + } + if (property == ANONYMOUS_CLASS_DECLARATION_PROPERTY) { + if (get) { + return getAnonymousClassDeclaration(); + } else { + setAnonymousClassDeclaration((AnonymousClassDeclaration) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalGetChildListProperty(ChildListPropertyDescriptor property) { + if (property == MODIFIERS2_PROPERTY) { + return modifiers(); + } + if (property == ARGUMENTS_PROPERTY) { + return arguments(); + } + // allow default implementation to flag the error + return super.internalGetChildListProperty(property); + } + + /* (omit javadoc for this method) + * Method declared on BodyDeclaration. + */ + final ChildPropertyDescriptor internalJavadocProperty() { + return JAVADOC_PROPERTY; + } + + /* (omit javadoc for this method) + * Method declared on BodyDeclaration. + */ + final ChildListPropertyDescriptor internalModifiers2Property() { + return MODIFIERS2_PROPERTY; + } + + /* (omit javadoc for this method) + * Method declared on BodyDeclaration. + */ + final SimplePropertyDescriptor internalModifiersProperty() { + // this property will not be asked for (node type did not exist in JLS2) + return null; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return ENUM_CONSTANT_DECLARATION; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + EnumConstantDeclaration result = new EnumConstantDeclaration(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setJavadoc( + (Javadoc) ASTNode.copySubtree(target, getJavadoc())); + result.modifiers().addAll(ASTNode.copySubtrees(target, modifiers())); + result.setName((SimpleName) getName().clone(target)); + result.arguments().addAll(ASTNode.copySubtrees(target, arguments())); + result.setAnonymousClassDeclaration( + (AnonymousClassDeclaration) ASTNode.copySubtree(target, getAnonymousClassDeclaration())); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + acceptChild(visitor, getJavadoc()); + acceptChildren(visitor, this.modifiers); + acceptChild(visitor, getName()); + acceptChildren(visitor, this.arguments); + acceptChild(visitor, getAnonymousClassDeclaration()); + } + visitor.endVisit(this); + } + + /** + * Returns the name of the constant declared in this enum declaration. + * + * @return the constant name node + */ + public SimpleName getName() { + if (this.constantName == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.constantName == null) { + preLazyInit(); + this.constantName = new SimpleName(this.ast); + postLazyInit(this.constantName, NAME_PROPERTY); + } + } + } + return this.constantName; + } + + /** + * Sets the name of the constant declared in this enum declaration to the + * given name. + * + * @param constantName the new constant name + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public void setName(SimpleName constantName) { + if (constantName == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.constantName; + preReplaceChild(oldChild, constantName, NAME_PROPERTY); + this.constantName = constantName; + postReplaceChild(oldChild, constantName, NAME_PROPERTY); + } + + /** + * Returns the live ordered list of argument expressions in this enumeration + * constant declaration. Note that an empty list of arguments is equivalent + * to not explicitly specifying arguments. + * + * @return the live list of argument expressions + * (element type: <code>Expression</code>) + */ + public List arguments() { + return this.arguments; + } + + /** + * Returns the anonymous class declaration introduced by this + * enum constant declaration, if it has one. + * + * @return the anonymous class declaration, or <code>null</code> if none + */ + public AnonymousClassDeclaration getAnonymousClassDeclaration() { + return this.optionalAnonymousClassDeclaration; + } + + /** + * Sets whether this enum constant declaration declares + * an anonymous class (that is, has class body declarations). + * + * @param decl the anonymous class declaration, or <code>null</code> + * if none + */ + public void setAnonymousClassDeclaration(AnonymousClassDeclaration decl) { + ASTNode oldChild = this.optionalAnonymousClassDeclaration; + preReplaceChild(oldChild, decl, ANONYMOUS_CLASS_DECLARATION_PROPERTY); + this.optionalAnonymousClassDeclaration = decl; + postReplaceChild(oldChild, decl, ANONYMOUS_CLASS_DECLARATION_PROPERTY); + } + + /** + * Resolves and returns the binding for the constructor invoked by this + * enum constant. + * <p> + * Note that bindings are generally unavailable unless requested when the + * AST is being built. + * </p> + * + * @return the constructor binding, or <code>null</code> if the binding + * cannot be resolved + */ + public IMethodBinding resolveConstructorBinding() { + return this.ast.getBindingResolver().resolveConstructor(this); + } + + /** + * Resolves and returns the field binding for this enum constant. + * <p> + * Note that bindings are generally unavailable unless requested when the + * AST is being built. + * </p> + * + * @return the binding, or <code>null</code> if the binding cannot be + * resolved + */ + public IVariableBinding resolveVariable() { + return this.ast.getBindingResolver().resolveVariable(this); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return super.memSize() + 3 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.optionalDocComment == null ? 0 : getJavadoc().treeSize()) + + this.modifiers.listSize() + + (this.constantName == null ? 0 : getName().treeSize()) + + this.arguments.listSize() + + (this.optionalAnonymousClassDeclaration == null ? 0 : getAnonymousClassDeclaration().treeSize()); + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/EnumDeclaration.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/EnumDeclaration.java new file mode 100644 index 000000000..d6f61c878 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/EnumDeclaration.java @@ -0,0 +1,335 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Enum declaration AST node type (added in JLS3 API). + * + * <pre> + * EnumDeclaration: + * [ Javadoc ] { ExtendedModifier } <b>enum</b> Identifier + * [ <b>implements</b> Type { <b>,</b> Type } ] + * <b>{</b> + * [ EnumConstantDeclaration { <b>,</b> EnumConstantDeclaration } ] [ <b>,</b> ] + * [ <b>;</b> { ClassBodyDeclaration | <b>;</b> } ] + * <b>}</b> + * </pre> + * The {@link #enumConstants()} list holds the enum constant declarations, + * while the {@link #bodyDeclarations()} list holds the class body declarations + * that appear after the semicolon. + * <p> + * When a Javadoc comment is present, the source + * range begins with the first character of the "/**" comment delimiter. + * When there is no Javadoc comment, the source range begins with the first + * character of the first modifier or annotation (if present), or the + * first character of the "enum" keyword (if no + * modifiers or annotations). The source range extends through the last + * character of the "}" token following the body declarations. + * </p> + * + * @since 3.1 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class EnumDeclaration extends AbstractTypeDeclaration { + + /** + * The "javadoc" structural property of this node type. + */ + public static final ChildPropertyDescriptor JAVADOC_PROPERTY = + internalJavadocPropertyFactory(EnumDeclaration.class); + + /** + * The "modifiers" structural property of this node type (added in JLS3 API). + */ + public static final ChildListPropertyDescriptor MODIFIERS2_PROPERTY = + internalModifiers2PropertyFactory(EnumDeclaration.class); + + /** + * The "name" structural property of this node type. + */ + public static final ChildPropertyDescriptor NAME_PROPERTY = + internalNamePropertyFactory(EnumDeclaration.class); + + /** + * The "superInterfaceTypes" structural property of this node type. + */ + public static final ChildListPropertyDescriptor SUPER_INTERFACE_TYPES_PROPERTY = + new ChildListPropertyDescriptor(EnumDeclaration.class, "superInterfaceTypes", Type.class, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "enumConstants" structural property of this node type. + */ + public static final ChildListPropertyDescriptor ENUM_CONSTANTS_PROPERTY = + new ChildListPropertyDescriptor(EnumDeclaration.class, "enumConstants", EnumConstantDeclaration.class, CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "bodyDeclarations" structural property of this node type. + */ + public static final ChildListPropertyDescriptor BODY_DECLARATIONS_PROPERTY = + internalBodyDeclarationPropertyFactory(EnumDeclaration.class); + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List properyList = new ArrayList(6); + createPropertyList(EnumDeclaration.class, properyList); + addProperty(JAVADOC_PROPERTY, properyList); + addProperty(MODIFIERS2_PROPERTY, properyList); + addProperty(NAME_PROPERTY, properyList); + addProperty(SUPER_INTERFACE_TYPES_PROPERTY, properyList); + addProperty(ENUM_CONSTANTS_PROPERTY, properyList); + addProperty(BODY_DECLARATIONS_PROPERTY, properyList); + PROPERTY_DESCRIPTORS = reapPropertyList(properyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The superinterface types (element type: <code>Type</code>). + * Defaults to an empty list. + */ + private ASTNode.NodeList superInterfaceTypes = + new ASTNode.NodeList(SUPER_INTERFACE_TYPES_PROPERTY); + + /** + * The enum constant declarations + * (element type: <code>EnumConstantDeclaration</code>). + * Defaults to an empty list. + */ + private ASTNode.NodeList enumConstants = + new ASTNode.NodeList(ENUM_CONSTANTS_PROPERTY); + + /** + * Creates a new AST node for an enum declaration owned by the given + * AST. By default, the enum declaration has an unspecified, but legal, + * name; no modifiers; no javadoc; no superinterfaces; + * and empty lists of enum constants and body declarations. + * <p> + * N.B. This constructor is package-private; all subclasses must be + * declared in the same package; clients are unable to declare + * additional subclasses. + * </p> + * + * @param ast the AST that is to own this node + */ + EnumDeclaration(AST ast) { + super(ast); + unsupportedIn2(); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == JAVADOC_PROPERTY) { + if (get) { + return getJavadoc(); + } else { + setJavadoc((Javadoc) child); + return null; + } + } + if (property == NAME_PROPERTY) { + if (get) { + return getName(); + } else { + setName((SimpleName) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalGetChildListProperty(ChildListPropertyDescriptor property) { + if (property == MODIFIERS2_PROPERTY) { + return modifiers(); + } + if (property == SUPER_INTERFACE_TYPES_PROPERTY) { + return superInterfaceTypes(); + } + if (property == ENUM_CONSTANTS_PROPERTY) { + return enumConstants(); + } + if (property == BODY_DECLARATIONS_PROPERTY) { + return bodyDeclarations(); + } + // allow default implementation to flag the error + return super.internalGetChildListProperty(property); + } + + /* (omit javadoc for this method) + * Method declared on BodyDeclaration. + */ + final ChildPropertyDescriptor internalJavadocProperty() { + return JAVADOC_PROPERTY; + } + + /* (omit javadoc for this method) + * Method declared on BodyDeclaration. + */ + final ChildListPropertyDescriptor internalModifiers2Property() { + return MODIFIERS2_PROPERTY; + } + + /* (omit javadoc for this method) + * Method declared on BodyDeclaration. + */ + final SimplePropertyDescriptor internalModifiersProperty() { + // this property will not be asked for (node type did not exist in JLS2) + return null; + } + + /* (omit javadoc for this method) + * Method declared on AbstractTypeDeclaration. + */ + final ChildPropertyDescriptor internalNameProperty() { + return NAME_PROPERTY; + } + + /* (omit javadoc for this method) + * Method declared on AbstractTypeDeclaration. + */ + final ChildListPropertyDescriptor internalBodyDeclarationsProperty() { + return BODY_DECLARATIONS_PROPERTY; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return ENUM_DECLARATION; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + EnumDeclaration result = new EnumDeclaration(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setJavadoc( + (Javadoc) ASTNode.copySubtree(target, getJavadoc())); + result.modifiers().addAll(ASTNode.copySubtrees(target, modifiers())); + result.setName((SimpleName) getName().clone(target)); + result.superInterfaceTypes().addAll( + ASTNode.copySubtrees(target, superInterfaceTypes())); + result.enumConstants().addAll( + ASTNode.copySubtrees(target, enumConstants())); + result.bodyDeclarations().addAll( + ASTNode.copySubtrees(target, bodyDeclarations())); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + acceptChild(visitor, getJavadoc()); + acceptChildren(visitor, this.modifiers); + acceptChild(visitor, getName()); + acceptChildren(visitor, this.superInterfaceTypes); + acceptChildren(visitor, this.enumConstants); + acceptChildren(visitor, this.bodyDeclarations); + } + visitor.endVisit(this); + } + + /** + * Returns the live ordered list of superinterfaces of this enum + * declaration. + * + * @return the live list of super interface types + * (element type: <code>Type</code>) + */ + public List superInterfaceTypes() { + return this.superInterfaceTypes; + } + + /** + * Returns the live ordered list of enum constant declarations + * of this enum declaration. + * + * @return the live list of enum constant declarations + * (element type: {@link EnumConstantDeclaration}) + */ + public List enumConstants() { + return this.enumConstants; + } + + /* (omit javadoc for this method) + * Method declared on AsbtractTypeDeclaration. + */ + ITypeBinding internalResolveBinding() { + return this.ast.getBindingResolver().resolveType(this); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return super.memSize() + 2 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return memSize() + + (this.optionalDocComment == null ? 0 : getJavadoc().treeSize()) + + this.modifiers.listSize() + + (this.typeName == null ? 0 : getName().treeSize()) + + this.superInterfaceTypes.listSize() + + this.enumConstants.listSize() + + this.bodyDeclarations.listSize(); + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Expression.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Expression.java new file mode 100644 index 000000000..f0ed33ed2 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Expression.java @@ -0,0 +1,140 @@ +/******************************************************************************* + * Copyright (c) 2000, 2009 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +/** + * Abstract base class of AST nodes that represent expressions. + * There are several kinds of expressions. + * <p> + * <pre> + * Expression: + * Name + * IntegerLiteral (includes decimal, hex, and octal forms; and long) + * FloatingPointLiteral (includes both float and double) + * CharacterLiteral + * NullLiteral + * BooleanLiteral + * StringLiteral + * TypeLiteral + * ThisExpression + * SuperFieldAccess + * FieldAccess + * Assignment + * ParenthesizedExpression + * ClassInstanceCreation + * ArrayCreation + * ArrayInitializer + * MethodInvocation + * SuperMethodInvocation + * ArrayAccess + * InfixExpression + * InstanceofExpression + * ConditionalExpression + * PostfixExpression + * PrefixExpression + * CastExpression + * VariableDeclarationExpression + * </pre> + * </p> + * + * @since 2.0 + */ +public abstract class Expression extends ASTNode { + + /** + * Creates a new AST node for an expression owned by the given AST. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + Expression(AST ast) { + super(ast); + } + + /** + * Resolves and returns the compile-time constant expression value as + * specified in JLS2 15.28, if this expression has one. Constant expression + * values are unavailable unless bindings are requested when the AST is + * being built. If the type of the value is a primitive type, the result + * is the boxed equivalent (i.e., int returned as an <code>Integer</code>); + * if the type of the value is <code>String</code>, the result is the string + * itself. If the expression does not have a compile-time constant expression + * value, the result is <code>null</code>. + * <p> + * Resolving constant expressions takes into account the value of simple + * and qualified names that refer to constant variables (JLS2 4.12.4). + * </p> + * <p> + * Note 1: enum constants are not considered constant expressions. + * The result is always <code>null</code> for these. + * </p> + * <p> + * Note 2: Compile-time constant expressions cannot denote <code>null</code>. + * So technically {@link NullLiteral} nodes are not constant expressions. + * The result is <code>null</code> for these nonetheless. + * </p> + * + * @return the constant expression value, or <code>null</code> if this + * expression has no constant expression value or if bindings were not + * requested when the AST was created + * @since 3.1 + */ + public final Object resolveConstantExpressionValue() { + return this.ast.getBindingResolver().resolveConstantExpressionValue(this); + } + + /** + * Resolves and returns the binding for the type of this expression. + * <p> + * Note that bindings are generally unavailable unless requested when the + * AST is being built. + * </p> + * + * @return the binding for the type of this expression, or + * <code>null</code> if the type cannot be resolved + */ + public final ITypeBinding resolveTypeBinding() { + return this.ast.getBindingResolver().resolveExpressionType(this); + } + + /** + * Returns whether this expression node is the site of a boxing + * conversion (JLS3 5.1.7). This information is available only + * when bindings are requested when the AST is being built. + * + * @return <code>true</code> if this expression is the site of a + * boxing conversion, or <code>false</code> if either no boxing conversion + * is involved or if bindings were not requested when the AST was created + * @since 3.1 + */ + public final boolean resolveBoxing() { + return this.ast.getBindingResolver().resolveBoxing(this); + } + + /** + * Returns whether this expression node is the site of an unboxing + * conversion (JLS3 5.1.8). This information is available only + * when bindings are requested when the AST is being built. + * + * @return <code>true</code> if this expression is the site of an + * unboxing conversion, or <code>false</code> if either no unboxing + * conversion is involved or if bindings were not requested when the + * AST was created + * @since 3.1 + */ + public final boolean resolveUnboxing() { + return this.ast.getBindingResolver().resolveUnboxing(this); + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ExpressionStatement.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ExpressionStatement.java new file mode 100644 index 000000000..14854db28 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ExpressionStatement.java @@ -0,0 +1,205 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Expression statement AST node type. + * <p> + * This kind of node is used to convert an expression (<code>Expression</code>) + * into a statement (<code>Statement</code>) by wrapping it. + * </p> + * <pre> + * ExpressionStatement: + * StatementExpression <b>;</b> + * </pre> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class ExpressionStatement extends Statement { + + /** + * The "expression" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor EXPRESSION_PROPERTY = + new ChildPropertyDescriptor(ExpressionStatement.class, "expression", Expression.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List properyList = new ArrayList(2); + createPropertyList(ExpressionStatement.class, properyList); + addProperty(EXPRESSION_PROPERTY, properyList); + PROPERTY_DESCRIPTORS = reapPropertyList(properyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The expression; lazily initialized; defaults to a unspecified, but legal, + * expression. + */ + private Expression expression = null; + + /** + * Creates a new unparented expression statement node owned by the given + * AST. By default, the expression statement is unspecified, but legal, + * method invocation expression. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + ExpressionStatement(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == EXPRESSION_PROPERTY) { + if (get) { + return getExpression(); + } else { + setExpression((Expression) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return EXPRESSION_STATEMENT; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + ExpressionStatement result = new ExpressionStatement(target); + result.setSourceRange(getStartPosition(), getLength()); + result.copyLeadingComment(this); + result.setExpression((Expression) getExpression().clone(target)); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + acceptChild(visitor, getExpression()); + } + visitor.endVisit(this); + } + + /** + * Returns the expression of this expression statement. + * + * @return the expression node + */ + public Expression getExpression() { + if (this.expression == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.expression == null) { + preLazyInit(); + this.expression = new MethodInvocation(this.ast); + postLazyInit(this.expression, EXPRESSION_PROPERTY); + } + } + } + return this.expression; + } + + /** + * Sets the expression of this expression statement. + * + * @param expression the new expression node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setExpression(Expression expression) { + if (expression == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.expression; + preReplaceChild(oldChild, expression, EXPRESSION_PROPERTY); + this.expression = expression; + postReplaceChild(oldChild, expression, EXPRESSION_PROPERTY); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return super.memSize() + 1 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.expression == null ? 0 : getExpression().treeSize()); + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/FieldAccess.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/FieldAccess.java new file mode 100644 index 000000000..ad9ac5140 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/FieldAccess.java @@ -0,0 +1,313 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Field access expression AST node type. + * + * <pre> + * FieldAccess: + * Expression <b>.</b> Identifier + * </pre> + * + * <p> + * Note that there are several kinds of expressions that resemble field access + * expressions: qualified names, this expressions, and super field access + * expressions. The following guidelines help with correct usage: + * <ul> + * <li>An expression like "foo.this" can only be represented as a this + * expression (<code>ThisExpression</code>) containing a simple name. + * "this" is a keyword, and therefore invalid as an identifier.</li> + * <li>An expression like "this.foo" can only be represented as a field + * access expression (<code>FieldAccess</code>) containing a this expression + * and a simple name. Again, this is because "this" is a keyword, and + * therefore invalid as an identifier.</li> + * <li>An expression with "super" can only be represented as a super field + * access expression (<code>SuperFieldAccess</code>). "super" is a also + * keyword, and therefore invalid as an identifier.</li> + * <li>An expression like "foo.bar" can be represented either as a + * qualified name (<code>QualifiedName</code>) or as a field access + * expression (<code>FieldAccess</code>) containing simple names. Either + * is acceptable, and there is no way to choose between them without + * information about what the names resolve to + * (<code>ASTParser</code> may return either).</li> + * <li>Other expressions ending in an identifier, such as "foo().bar" can + * only be represented as field access expressions + * (<code>FieldAccess</code>).</li> + * </ul> + * </p> + * + * @see QualifiedName + * @see ThisExpression + * @see SuperFieldAccess + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class FieldAccess extends Expression { + + /** + * The "expression" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor EXPRESSION_PROPERTY = + new ChildPropertyDescriptor(FieldAccess.class, "expression", Expression.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "name" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor NAME_PROPERTY = + new ChildPropertyDescriptor(FieldAccess.class, "name", SimpleName.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List properyList = new ArrayList(3); + createPropertyList(FieldAccess.class, properyList); + addProperty(EXPRESSION_PROPERTY, properyList); + addProperty(NAME_PROPERTY, properyList); + PROPERTY_DESCRIPTORS = reapPropertyList(properyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The expression; lazily initialized; defaults to an unspecified, + * but legal, simple name. + */ + private Expression expression = null; + + /** + * The field; lazily initialized; defaults to an unspecified, + * but legal, simple field name. + */ + private SimpleName fieldName = null; + + /** + * Creates a new unparented node for a field access expression owned by the + * given AST. By default, the expression and field are both unspecified, + * but legal, names. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + FieldAccess(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == EXPRESSION_PROPERTY) { + if (get) { + return getExpression(); + } else { + setExpression((Expression) child); + return null; + } + } + if (property == NAME_PROPERTY) { + if (get) { + return getName(); + } else { + setName((SimpleName) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return FIELD_ACCESS; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + FieldAccess result = new FieldAccess(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setExpression((Expression) getExpression().clone(target)); + result.setName((SimpleName) getName().clone(target)); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + acceptChild(visitor, getExpression()); + acceptChild(visitor, getName()); + } + visitor.endVisit(this); + } + + /** + * Returns the expression of this field access expression. + * + * @return the expression node + */ + public Expression getExpression() { + if (this.expression == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.expression == null) { + preLazyInit(); + this.expression = new SimpleName(this.ast); + postLazyInit(this.expression, EXPRESSION_PROPERTY); + } + } + } + return this.expression; + } + + /** + * Sets the expression of this field access expression. + * + * @param expression the new expression + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setExpression(Expression expression) { + if (expression == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.expression; + preReplaceChild(oldChild, expression, EXPRESSION_PROPERTY); + this.expression = expression; + postReplaceChild(oldChild, expression, EXPRESSION_PROPERTY); + } + + /** + * Returns the name of the field accessed in this field access expression. + * + * @return the field name + */ + public SimpleName getName() { + if (this.fieldName == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.fieldName == null) { + preLazyInit(); + this.fieldName = new SimpleName(this.ast); + postLazyInit(this.fieldName, NAME_PROPERTY); + } + } + } + return this.fieldName; + } + + /** + * Sets the name of the field accessed in this field access expression. + * + * @param fieldName the field name + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public void setName(SimpleName fieldName) { + if (fieldName == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.fieldName; + preReplaceChild(oldChild, fieldName, NAME_PROPERTY); + this.fieldName = fieldName; + postReplaceChild(oldChild, fieldName, NAME_PROPERTY); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + // treat Code as free + return BASE_NODE_SIZE + 2 * 4; + } + + /** + * Resolves and returns the binding for the field accessed by this + * expression. + * <p> + * Note that bindings are generally unavailable unless requested when the + * AST is being built. + * </p> + * + * @return the variable binding, or <code>null</code> if the binding cannot + * be resolved + * @since 3.0 + */ + public IVariableBinding resolveFieldBinding() { + return this.ast.getBindingResolver().resolveField(this); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.expression == null ? 0 : getExpression().treeSize()) + + (this.fieldName == null ? 0 : getName().treeSize()); + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/FieldAccessSpec.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/FieldAccessSpec.java new file mode 100644 index 000000000..9b587c43d --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/FieldAccessSpec.java @@ -0,0 +1,294 @@ +/********************************************************************** + * This file is part of "Object Teams Development Tooling"-Software + * + * Copyright 2004, 2006 Fraunhofer Gesellschaft, Munich, Germany, + * for its Fraunhofer Institute for Computer Architecture and Software + * Technology (FIRST), Berlin, Germany and Technical University Berlin, + * Germany. + * + * 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 + * $Id: FieldAccessSpec.java 23416 2010-02-03 19:59:31Z stephan $ + * + * Please visit http://www.eclipse.org/objectteams for updates and contact. + * + * Contributors: + * Fraunhofer FIRST - Initial API and implementation + * Technical University Berlin - Initial API and implementation + **********************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * NEW for OTDT + * + * + * Represents DOM-ASTNode for callout binding to a field of the corresponding base class (OTJLD §3.5), + * which has to handle code from e.g. : + * get value + * set value + * to e.g. : + * get int value + * set String value + * + * This class has following properties: + * modifiers (JLS2) or isSetter (JLS3) + * fieldType, + * name, + * signature + * + * This node can be used only in CalloutMethodDeclaration. + * + * @author jsv + */ +public class FieldAccessSpec extends MethodMappingElement +{ + /** + * The "signature" structural property of this node type. + */ + public static final SimplePropertyDescriptor SIGNATURE_PROPERTY = + internalSignaturePropertyFactory(FieldAccessSpec.class); + + /** + * The "name" structural property of this node type. + */ + public static final ChildPropertyDescriptor NAME_PROPERTY = + internalNamePropertyFactory(FieldAccessSpec.class); + + /** + * The "fieldType" structural property of this node type. + */ + public static final ChildPropertyDescriptor FIELD_TYPE_PROPERTY = + new ChildPropertyDescriptor(FieldAccessSpec.class, "fieldType", Type.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS_2_0; + + private static final List PROPERTY_DESCRIPTORS_3_0; + + static + { + List propertyList = new ArrayList(4); + createPropertyList(FieldAccessSpec.class, propertyList); + addProperty(SIGNATURE_PROPERTY, propertyList); + addProperty(NAME_PROPERTY, propertyList); + addProperty(FIELD_TYPE_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS_2_0 = reapPropertyList(propertyList); + + propertyList = new ArrayList(4); + createPropertyList(FieldAccessSpec.class, propertyList); + addProperty(SIGNATURE_PROPERTY, propertyList); + addProperty(NAME_PROPERTY, propertyList); + addProperty(FIELD_TYPE_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS_3_0 = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the AST.JLS* constants + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + */ + public static List propertyDescriptors(int apiLevel) + { + if (apiLevel == AST.JLS2_INTERNAL) + return PROPERTY_DESCRIPTORS_2_0; + else + return PROPERTY_DESCRIPTORS_3_0; + } + + boolean isSetter = false; + + /** + * The field type. + * JLS2 behevior: lazily initialized; defaults to void. + * Note that this field is ignored for constructor declarations. + */ + private Type _fieldType = null; + + FieldAccessSpec(AST ast) + { + super(ast); + } + + final List internalStructuralPropertiesForType(int apiLevel) + { + return propertyDescriptors(apiLevel); + } + + final boolean internalGetSetBooleanProperty(SimplePropertyDescriptor property, boolean isGetRequest, boolean value) + { + if (property == SIGNATURE_PROPERTY) + { + if (isGetRequest) + { + return hasSignature(); + } + else + { + setSignatureFlag(value); + return false; + } + } + return super.internalGetSetBooleanProperty(property, isGetRequest, value); + } + + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean isGetRequest, ASTNode child) + { + if (property == NAME_PROPERTY) + { + if (isGetRequest) + { + return getName(); + } + else + { + setName((SimpleName) child); + return null; + } + } + if (property == FIELD_TYPE_PROPERTY) + { + if (isGetRequest) + { + return getFieldType(); + } + else + { + setFieldType((Type) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, isGetRequest, child); + } + + SimplePropertyDescriptor internalSignatureProperty() { + return SIGNATURE_PROPERTY; + } + + ChildPropertyDescriptor internalNameProperty() { + return NAME_PROPERTY; + } + + final int getNodeType0() + { + return FIELD_ACCESS_SPEC; + } + + ASTNode clone0(AST target) + { + FieldAccessSpec result = new FieldAccessSpec(target); + result.setSourceRange(this.getStartPosition(), this.getLength()); + result.setSignatureFlag(this.hasSignature()); + result.setName((SimpleName) this.getName().clone(target)); + result.setFieldType( + (Type) ASTNode.copySubtree(target, getFieldType())); + return result; + } + + void accept0(ASTVisitor visitor) + { + boolean visitChildren = visitor.visit(this); + if (visitChildren) + { + // visit children in normal left to right reading order + acceptChild(visitor, getFieldType()); + acceptChild(visitor, getName()); + } + visitor.endVisit(this); + } + + final boolean subtreeMatch0(ASTMatcher matcher, Object other) + { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + int treeSize() + { + return memSize() + + (this.getName() == null ? 0 : getName().treeSize()) + + (this.getFieldType() == null ? 0 : getFieldType().treeSize()); + } + + int memSize() + { + return BASE_NODE_SIZE + 3 * 4; + } + + /** + * Returns the field type of the field in this FieldAccessSpec, + * exclusive of any extra array dimensions (JLS2 API only). + * This is one of the few places where the void type is meaningful. + * <p> + * Note that this child is not relevant for constructor declarations + * (although, it does still figure in subtree equality comparisons + * and visits), and is devoid of the binding information ordinarily + * available. + * </p> + * + * @return the return type, possibly the void primitive type + */ + public Type getFieldType() + { + if (this._fieldType == null) + { + // lazy init must be thread-safe for readers + synchronized (this) + { + if (this._fieldType == null) + { + preLazyInit(); + this._fieldType = this.ast.newPrimitiveType(PrimitiveType.VOID); + postLazyInit(this._fieldType, FIELD_TYPE_PROPERTY); + } + } + } + return this._fieldType; + } + + /** + * Sets the field type of the field declared in this FieldAccessSpec + * declaration to the given type, exclusive of any extra array dimensions + * (JLS2 API only). This is one of the few places where the void type is meaningful. + * <p> + * Note that this child is not relevant for constructor declarations + * (although it does still figure in subtree equality comparisons and visits). + * </p> + * + * @param type the new return type, possibly the void primitive type + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public void setFieldType(Type type) + { + if (type == null) + { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this._fieldType; + preReplaceChild(oldChild, type, FIELD_TYPE_PROPERTY); + this._fieldType = type; + postReplaceChild(oldChild, type, FIELD_TYPE_PROPERTY); + } + + public IVariableBinding resolveBinding() { + return this.ast.getBindingResolver().resolveVariable(this); + } + +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/FieldDeclaration.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/FieldDeclaration.java new file mode 100644 index 000000000..d82bf6f4b --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/FieldDeclaration.java @@ -0,0 +1,368 @@ +/******************************************************************************* + * Copyright (c) 2000, 2009 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Field declaration node type. + * <p> + * This kind of node collects several variable declaration fragments + * (<code>VariableDeclarationFragment</code>) into a single body declaration + * (<code>BodyDeclaration</code>), all sharing the same modifiers and base type. + * </p> + * <pre> + * FieldDeclaration: + * [Javadoc] { ExtendedModifier } Type VariableDeclarationFragment + * { <b>,</b> VariableDeclarationFragment } <b>;</b> + * </pre> + * <p> + * When a Javadoc comment is present, the source range begins with the first + * character of the "/**" comment delimiter. When there is no Javadoc comment, + * the source range begins with the first character of the initial modifier or + * type. The source range extends through the last character of the final ";". + * </p> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class FieldDeclaration extends BodyDeclaration { + + /** + * The "javadoc" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor JAVADOC_PROPERTY = + internalJavadocPropertyFactory(FieldDeclaration.class); + + /** + * The "modifiers" structural property of this node type (JLS2 API only). + * @since 3.0 + */ + public static final SimplePropertyDescriptor MODIFIERS_PROPERTY = + internalModifiersPropertyFactory(FieldDeclaration.class); + + /** + * The "modifiers" structural property of this node type (added in JLS3 API). + * @since 3.1 + */ + public static final ChildListPropertyDescriptor MODIFIERS2_PROPERTY = + internalModifiers2PropertyFactory(FieldDeclaration.class); + + /** + * The "type" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor TYPE_PROPERTY = + new ChildPropertyDescriptor(FieldDeclaration.class, "type", Type.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "fragments" structural property of this node type). + * @since 3.0 + */ + public static final ChildListPropertyDescriptor FRAGMENTS_PROPERTY = + new ChildListPropertyDescriptor(FieldDeclaration.class, "fragments", VariableDeclarationFragment.class, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + * @since 3.0 + */ + private static final List PROPERTY_DESCRIPTORS_2_0; + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + * @since 3.1 + */ + private static final List PROPERTY_DESCRIPTORS_3_0; + + static { + List properyList = new ArrayList(5); + createPropertyList(FieldDeclaration.class, properyList); + addProperty(JAVADOC_PROPERTY, properyList); + addProperty(MODIFIERS_PROPERTY, properyList); + addProperty(TYPE_PROPERTY, properyList); + addProperty(FRAGMENTS_PROPERTY, properyList); + PROPERTY_DESCRIPTORS_2_0 = reapPropertyList(properyList); + + properyList = new ArrayList(5); + createPropertyList(FieldDeclaration.class, properyList); + addProperty(JAVADOC_PROPERTY, properyList); + addProperty(MODIFIERS2_PROPERTY, properyList); + addProperty(TYPE_PROPERTY, properyList); + addProperty(FRAGMENTS_PROPERTY, properyList); + PROPERTY_DESCRIPTORS_3_0 = reapPropertyList(properyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + if (apiLevel == AST.JLS2_INTERNAL) { + return PROPERTY_DESCRIPTORS_2_0; + } else { + return PROPERTY_DESCRIPTORS_3_0; + } + } + + /** + * The base type; lazily initialized; defaults to an unspecified, + * legal type. + */ + private Type baseType = null; + + /** + * The list of variable declaration fragments (element type: + * {@link VariableDeclarationFragment}). Defaults to an empty list. + */ + private ASTNode.NodeList variableDeclarationFragments = + new ASTNode.NodeList(FRAGMENTS_PROPERTY); + + /** + * Creates a new unparented field declaration statement node owned + * by the given AST. By default, the field declaration has: no modifiers, + * an unspecified (but legal) type, and an empty list of variable + * declaration fragments (which is syntactically illegal). + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + FieldDeclaration(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + * @since 3.0 + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int internalGetSetIntProperty(SimplePropertyDescriptor property, boolean get, int value) { + if (property == MODIFIERS_PROPERTY) { + if (get) { + return getModifiers(); + } else { + internalSetModifiers(value); + return 0; + } + } + // allow default implementation to flag the error + return super.internalGetSetIntProperty(property, get, value); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == JAVADOC_PROPERTY) { + if (get) { + return getJavadoc(); + } else { + setJavadoc((Javadoc) child); + return null; + } + } + if (property == TYPE_PROPERTY) { + if (get) { + return getType(); + } else { + setType((Type) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalGetChildListProperty(ChildListPropertyDescriptor property) { + if (property == MODIFIERS2_PROPERTY) { + return modifiers(); + } + if (property == FRAGMENTS_PROPERTY) { + return fragments(); + } + // allow default implementation to flag the error + return super.internalGetChildListProperty(property); + } + + /* (omit javadoc for this method) + * Method declared on BodyDeclaration. + */ + final ChildPropertyDescriptor internalJavadocProperty() { + return JAVADOC_PROPERTY; + } + + /* (omit javadoc for this method) + * Method declared on BodyDeclaration. + */ + final SimplePropertyDescriptor internalModifiersProperty() { + return MODIFIERS_PROPERTY; + } + + /* (omit javadoc for this method) + * Method declared on BodyDeclaration. + */ + final ChildListPropertyDescriptor internalModifiers2Property() { + return MODIFIERS2_PROPERTY; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return FIELD_DECLARATION; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + FieldDeclaration result = new FieldDeclaration(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setJavadoc( + (Javadoc) ASTNode.copySubtree(target, getJavadoc())); + if (this.ast.apiLevel == AST.JLS2_INTERNAL) { + result.internalSetModifiers(getModifiers()); + } + if (this.ast.apiLevel >= AST.JLS3) { + result.modifiers().addAll(ASTNode.copySubtrees(target, modifiers())); + } + result.setType((Type) getType().clone(target)); + result.fragments().addAll( + ASTNode.copySubtrees(target, fragments())); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + acceptChild(visitor, getJavadoc()); + if (this.ast.apiLevel >= AST.JLS3) { + acceptChildren(visitor, this.modifiers); + } + acceptChild(visitor, getType()); + acceptChildren(visitor, this.variableDeclarationFragments); + } + visitor.endVisit(this); + } + + /** + * Returns the base type declared in this field declaration. + * <p> + * N.B. The individual child variable declaration fragments may specify + * additional array dimensions. So the type of the variable are not + * necessarily exactly this type. + * </p> + * + * @return the base type + */ + public Type getType() { + if (this.baseType == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.baseType == null) { + preLazyInit(); + this.baseType = this.ast.newPrimitiveType(PrimitiveType.INT); + postLazyInit(this.baseType, TYPE_PROPERTY); + } + } + } + return this.baseType; + } + + /** + * Sets the base type declared in this field declaration to the given type. + * + * @param type the new base type + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public void setType(Type type) { + if (type == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.baseType; + preReplaceChild(oldChild, type, TYPE_PROPERTY); + this.baseType = type; + postReplaceChild(oldChild, type, TYPE_PROPERTY); + } + + /** + * Returns the live list of variable declaration fragments in this field + * declaration. Adding and removing nodes from this list affects this node + * dynamically. All nodes in this list must be + * <code>VariableDeclarationFragment</code>s; attempts to add any other + * type of node will trigger an exception. + * + * @return the live list of variable declaration fragments in this + * statement (element type: <code>VariableDeclarationFragment</code>) + */ + public List fragments() { + return this.variableDeclarationFragments; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return super.memSize() + 2 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.optionalDocComment == null ? 0 : getJavadoc().treeSize()) + + (this.modifiers == null ? 0 : this.modifiers.listSize()) + + (this.baseType == null ? 0 : getType().treeSize()) + + this.variableDeclarationFragments.listSize(); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ForStatement.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ForStatement.java new file mode 100644 index 000000000..e9f56202e --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ForStatement.java @@ -0,0 +1,361 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * For statement AST node type. + * + * <pre> + * ForStatement: + * <b>for</b> <b>(</b> + * [ ForInit ]<b>;</b> + * [ Expression ] <b>;</b> + * [ ForUpdate ] <b>)</b> + * Statement + * ForInit: + * Expression { <b>,</b> Expression } + * ForUpdate: + * Expression { <b>,</b> Expression } + * </pre> + * <p> + * Note: When variables are declared in the initializer + * of a for statement such as "<code>for (int a=1, b=2;;);</code>", + * they should be represented as a single + * <code>VariableDeclarationExpression</code> + * with two fragments, rather than being split up into a pair + * of expressions. + * </p> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class ForStatement extends Statement { + + /** + * The "initializers" structural property of this node type. + * @since 3.0 + */ + public static final ChildListPropertyDescriptor INITIALIZERS_PROPERTY = + new ChildListPropertyDescriptor(ForStatement.class, "initializers", Expression.class, CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "expression" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor EXPRESSION_PROPERTY = + new ChildPropertyDescriptor(ForStatement.class, "expression", Expression.class, OPTIONAL, CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "updaters" structural property of this node type. + * @since 3.0 + */ + public static final ChildListPropertyDescriptor UPDATERS_PROPERTY = + new ChildListPropertyDescriptor(ForStatement.class, "updaters", Expression.class, CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "body" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor BODY_PROPERTY = + new ChildPropertyDescriptor(ForStatement.class, "body", Statement.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List properyList = new ArrayList(5); + createPropertyList(ForStatement.class, properyList); + addProperty(INITIALIZERS_PROPERTY, properyList); + addProperty(EXPRESSION_PROPERTY, properyList); + addProperty(UPDATERS_PROPERTY, properyList); + addProperty(BODY_PROPERTY, properyList); + PROPERTY_DESCRIPTORS = reapPropertyList(properyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The list of initializer expressions (element type: + * <code>Expression</code>). Defaults to an empty list. + */ + private ASTNode.NodeList initializers = + new ASTNode.NodeList(INITIALIZERS_PROPERTY); + + /** + * The condition expression; <code>null</code> for none; defaults to none. + */ + private Expression optionalConditionExpression = null; + + /** + * The list of update expressions (element type: + * <code>Expression</code>). Defaults to an empty list. + */ + private ASTNode.NodeList updaters = + new ASTNode.NodeList(UPDATERS_PROPERTY); + + /** + * The body statement; lazily initialized; defaults to an empty block + * statement. + */ + private Statement body = null; + + /** + * Creates a new AST node for a for statement owned by the given AST. + * By default, there are no initializers, no condition expression, + * no updaters, and the body is an empty block. + * + * @param ast the AST that is to own this node + */ + ForStatement(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == EXPRESSION_PROPERTY) { + if (get) { + return getExpression(); + } else { + setExpression((Expression) child); + return null; + } + } + if (property == BODY_PROPERTY) { + if (get) { + return getBody(); + } else { + setBody((Statement) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalGetChildListProperty(ChildListPropertyDescriptor property) { + if (property == INITIALIZERS_PROPERTY) { + return initializers(); + } + if (property == UPDATERS_PROPERTY) { + return updaters(); + } + // allow default implementation to flag the error + return super.internalGetChildListProperty(property); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return FOR_STATEMENT; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + ForStatement result = new ForStatement(target); + result.setSourceRange(getStartPosition(), getLength()); + result.copyLeadingComment(this); + result.initializers().addAll(ASTNode.copySubtrees(target, initializers())); + result.setExpression( + (Expression) ASTNode.copySubtree(target, getExpression())); + result.updaters().addAll(ASTNode.copySubtrees(target, updaters())); + result.setBody( + (Statement) ASTNode.copySubtree(target, getBody())); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + acceptChildren(visitor, this.initializers); + acceptChild(visitor, getExpression()); + acceptChildren(visitor, this.updaters); + acceptChild(visitor, getBody()); + } + visitor.endVisit(this); + } + + /** + * Returns the live ordered list of initializer expressions in this for + * statement. + * <p> + * The list should consist of either a list of so called statement + * expressions (JLS2, 14.8), or a single <code>VariableDeclarationExpression</code>. + * Otherwise, the for statement would have no Java source equivalent. + * </p> + * + * @return the live list of initializer expressions + * (element type: <code>Expression</code>) + */ + public List initializers() { + return this.initializers; + } + + /** + * Returns the condition expression of this for statement, or + * <code>null</code> if there is none. + * + * @return the condition expression node, or <code>null</code> if + * there is none + */ + public Expression getExpression() { + return this.optionalConditionExpression; + } + + /** + * Sets or clears the condition expression of this return statement. + * + * @param expression the condition expression node, or <code>null</code> + * if there is none + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setExpression(Expression expression) { + ASTNode oldChild = this.optionalConditionExpression; + preReplaceChild(oldChild, expression, EXPRESSION_PROPERTY); + this.optionalConditionExpression = expression; + postReplaceChild(oldChild, expression, EXPRESSION_PROPERTY); + } + + /** + * Returns the live ordered list of update expressions in this for + * statement. + * <p> + * The list should consist of so called statement expressions. Otherwise, + * the for statement would have no Java source equivalent. + * </p> + * + * @return the live list of update expressions + * (element type: <code>Expression</code>) + */ + public List updaters() { + return this.updaters; + } + + /** + * Returns the body of this for statement. + * + * @return the body statement node + */ + public Statement getBody() { + if (this.body == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.body == null) { + preLazyInit(); + this.body = new Block(this.ast); + postLazyInit(this.body, BODY_PROPERTY); + } + } + } + return this.body; + } + + /** + * Sets the body of this for statement. + * <p> + * Special note: The Java language does not allow a local variable declaration + * to appear as the body of a for statement (they may only appear within a + * block). However, the AST will allow a <code>VariableDeclarationStatement</code> + * as the body of a <code>ForStatement</code>. To get something that will + * compile, be sure to embed the <code>VariableDeclarationStatement</code> + * inside a <code>Block</code>. + * </p> + * + * @param statement the body statement node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setBody(Statement statement) { + if (statement == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.body; + preReplaceChild(oldChild, statement, BODY_PROPERTY); + this.body = statement; + postReplaceChild(oldChild, statement, BODY_PROPERTY); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return super.memSize() + 4 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + this.initializers.listSize() + + this.updaters.listSize() + + (this.optionalConditionExpression == null ? 0 : getExpression().treeSize()) + + (this.body == null ? 0 : getBody().treeSize()); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/GuardPredicateDeclaration.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/GuardPredicateDeclaration.java new file mode 100644 index 000000000..ee9ace527 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/GuardPredicateDeclaration.java @@ -0,0 +1,199 @@ +/********************************************************************** + * This file is part of "Object Teams Development Tooling"-Software + * + * Copyright 2006 Fraunhofer Gesellschaft, Munich, Germany, + * for its Fraunhofer Institute for Computer Architecture and Software + * Technology (FIRST), Berlin, Germany and Technical University Berlin, + * Germany. + * + * 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 + * $Id: GuardPredicateDeclaration.java 23417 2010-02-03 20:13:55Z stephan $ + * + * Please visit http://www.eclipse.org/objectteams for updates and contact. + * + * Contributors: + * Fraunhofer FIRST - Initial API and implementation + * Technical University Berlin - Initial API and implementation + **********************************************************************/ +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * This class represents a declaration of a guard predicate in OT/J (OTJLD §5.4). + * + * @author stephan + */ +public class GuardPredicateDeclaration extends ASTNode { + + /** + * Structural property for the boolean expression that represents the guard's implementation. + */ + public static final ChildPropertyDescriptor EXPRESSION_PROPERTY = + new ChildPropertyDescriptor(GuardPredicateDeclaration.class, "expression", Expression.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "base" structural property of this node type, marking whether it is a "base guard" or not. + */ + public static final SimplePropertyDescriptor BASE_PROPERTY = + new SimplePropertyDescriptor(GuardPredicateDeclaration.class, "base", boolean.class, MANDATORY); //$NON-NLS-1$ + + + private static final List PROPERTY_DESCRIPTORS_3_0; + + static { + List propertyList = new ArrayList(3); + createPropertyList(GuardPredicateDeclaration.class, propertyList); + addProperty(BASE_PROPERTY, propertyList); + addProperty(EXPRESSION_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS_3_0 = reapPropertyList(propertyList); + } + + public static List propertyDescriptors(int apiLevel) { + if (apiLevel == AST.JLS2_INTERNAL) { + throw new UnsupportedOperationException("JLS2 not supported"); //$NON-NLS-1$ + } else { + return PROPERTY_DESCRIPTORS_3_0; + } + } + + private Expression expression = null; + private boolean isBase = false; + + GuardPredicateDeclaration(AST ast) + { + super(ast); + } + + @Override + boolean internalGetSetBooleanProperty(SimplePropertyDescriptor property, boolean get, boolean value) + { + if (property == BASE_PROPERTY) { + if (get) { + return isBase(); + } else { + setBase(value); + return false; + } + } + // allow default implementation to flag the error + return super.internalGetSetBooleanProperty(property, get, value); + } + + @Override + ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) + { + if (property == EXPRESSION_PROPERTY) { + if (get) { + return getExpression(); + } else { + setExpression((Expression)child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + @Override + int getNodeType0() { + return GUARD_PREDICATE_DECLARATION; + } + + @Override + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + if (this.ast.apiLevel == AST.JLS2_INTERNAL) { + unsupportedIn2(); + } + if (this.ast.apiLevel >= AST.JLS3) { + acceptChild(visitor, this.expression); + } + } + visitor.endVisit(this); + } + + @Override + boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + @Override + ASTNode clone0(AST target) { + if (this.ast.apiLevel == AST.JLS2_INTERNAL) + unsupportedIn2(); + GuardPredicateDeclaration result = new GuardPredicateDeclaration(target); + result.setSourceRange(this.getStartPosition(), this.getLength()); + result.setBase(this.isBase()); + result.setExpression((Expression)ASTNode.copySubtree(target, getExpression())); + return result; + } + + public boolean isBase() + { + return isBase; + } + + public void setBase(boolean isBase) + { + preValueChange(BASE_PROPERTY); + this.isBase = isBase; + postValueChange(BASE_PROPERTY); + } + + + public ASTNode getExpression() { + if (this.expression == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.expression == null) { + preLazyInit(); + this.expression = new SimpleName(this.ast); + postLazyInit(this.expression, EXPRESSION_PROPERTY); + } + } + } + return this.expression; + } + + public void setExpression(Expression expression) { + if (expression == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.expression; + preReplaceChild(oldChild, expression, EXPRESSION_PROPERTY); + this.expression = expression; + postReplaceChild(oldChild, expression, EXPRESSION_PROPERTY); + } + + @Override + List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + @Override + void appendDebugString(StringBuffer buffer) { + if (this.isBase) + buffer.append("base "); //$NON-NLS-1$ + buffer.append("when ("); //$NON-NLS-1$ + this.expression.appendDebugString(buffer); + buffer.append(")"); //$NON-NLS-1$ + } + + @Override + int memSize() { + return BASE_NODE_SIZE; // FIXME(SH) + plus some constant?? + } + + @Override + int treeSize() { + return memSize() + (this.expression == null ? 0 : getExpression().treeSize()); + } + +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IAnnotationBinding.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IAnnotationBinding.java new file mode 100644 index 000000000..5f6c10e5f --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IAnnotationBinding.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2005, 2008 BEA Systems, Inc. + * 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: + * tyeung@bea.com - initial API and implementation + * IBM Corporation - changed interface to extend IBinding + * IBM Corporation - renamed from IResolvedAnnotation to IAnnotationBinding + *******************************************************************************/ +package org.eclipse.jdt.core.dom; + +/** + * Represents a resolved annotation. Resolved annotations are computed along with other + * bindings; they correspond to {@link Annotation} nodes. + * + * @since 3.2 + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface IAnnotationBinding extends IBinding { + + /** + * Returns the complete list of member value pairs for this annotation, including + * ones explicitly listed in the annotation as well as entries for + * annotation type members with default values that are implied. + * + * @return a possibly empty list of resolved member value pairs + */ + IMemberValuePairBinding[] getAllMemberValuePairs(); + + /** + * Returns the type of the annotation. The resulting type binding will always + * return <code>true</code> to <code>ITypeBinding.isAnnotation()</code>. + * + * @return the type of the annotation + */ + ITypeBinding getAnnotationType(); + + /** + * Returns the list of declared member value pairs for this annotation. + * Returns an empty list for a {@link MarkerAnnotation}, a one element + * list for a {@link SingleMemberAnnotation}, and one entry for each + * of the explicitly listed values in a {@link NormalAnnotation}. + * <p> + * Note that the list only includes entries for annotation type members that are + * explicitly mentioned in the annotation. The list does not include any + * annotation type members with default values that are merely implied. + * Use {@link #getAllMemberValuePairs()} to get those as well. + * </p> + * + * @return a possibly empty list of resolved member value pairs + */ + IMemberValuePairBinding[] getDeclaredMemberValuePairs(); + + /** + * Returns the name of the annotation type. + * + * @return the name of the annotation type + */ + public String getName(); + +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IBinding.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IBinding.java new file mode 100644 index 000000000..b185e662f --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IBinding.java @@ -0,0 +1,340 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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 + * $Id: IBinding.java 19895 2009-04-15 13:52:23Z stephan $ + * + * Contributors: + * IBM Corporation - initial API and implementation + * Fraunhofer FIRST - extended API and implementation + * Technical University Berlin - extended API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import org.eclipse.jdt.core.IAnnotation; +import org.eclipse.jdt.core.IJavaElement; + +/** + * A binding represents a named entity in the Java language. The world of + * bindings provides an integrated picture of the structure of the program as + * seen from the compiler's point of view. This interface declare protocol + * common to the various different kinds of named entities in the Java language: + * packages, types, fields, methods, constructors, and local variables. + * + * @see IPackageBinding + * @see ITypeBinding + * @see IVariableBinding + * @see IMethodBinding + * @see IAnnotationBinding + * @see IMemberValuePairBinding + * @since 2.0 + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface IBinding { + + /** + * Kind constant (value 1) indicating a package binding. + * Bindings of this kind can be safely cast to <code>IPackageBinding</code>. + * + * @see #getKind() + * @see IPackageBinding + */ + public static final int PACKAGE = 1; + + /** + * Kind constant (value 2) indicating a type binding. + * Bindings of this kind can be safely cast to <code>ITypeBinding</code>. + * + * @see #getKind() + * @see ITypeBinding + */ + public static final int TYPE = 2; + + /** + * Kind constant (value 3) indicating a field or local variable binding. + * Bindings of this kind can be safely cast to <code>IVariableBinding</code>. + * + * @see #getKind() + * @see IVariableBinding + */ + public static final int VARIABLE = 3; + + /** + * Kind constant (value 4) indicating a method or constructor binding. + * Bindings of this kind can be safely cast to <code>IMethodBinding</code>. + * + * @see #getKind() + * @see IMethodBinding + */ + public static final int METHOD = 4; + + /** + * Kind constant (value 5) indicating an annotation binding. + * Bindings of this kind can be safely cast to <code>IAnnotationBinding</code>. + * + * @see #getKind() + * @see IAnnotationBinding + * @since 3.2 + */ + public static final int ANNOTATION = 5; + + /** + * Kind constant (value 6) indicating a member value pair binding. + * Bindings of this kind can be safely cast to <code>IMemberValuePairBinding</code>. + * + * @see #getKind() + * @see IMemberValuePairBinding + * @since 3.2 + */ + public static final int MEMBER_VALUE_PAIR = 6; + +//{ObjectTeams: Binding for method mappings. + /** + * Kind constant (value 7) indicating a callin/callout method mapping. + * Bindings of this kind can be safely cast to <code>IMethodMappingBinding</code>. + * + * @see #getKind() + * @see IMethodMappingBinding + */ + public static final int METHOD_MAPPING = 7; +//mkr} + + /** + * Return the resolved annotations associated with this binding. + * <ul> + * <li>Package bindings - these are annotations on a package declaration. + * </li> + * <li>Type bindings - these are annotations on a class, interface, enum, + * or annotation type declaration. The result is the same regardless of + * whether the type is parameterized.</li> + * <li>Method bindings - these are annotations on a method or constructor + * declaration. The result is the same regardless of whether the method is + * parameterized.</li> + * <li>Variable bindings - these are annotations on a field, enum constant, + * or formal parameter declaration.</li> + * <li>Annotation bindings - an empty array is always returned</li> + * <li>Member value pair bindings - an empty array is always returned</li> + * </ul> + * + * @return the list of resolved annotations, or the empty list if there are no + * annotations associated with the object + * @since 3.2 + */ + public IAnnotationBinding[] getAnnotations(); + + /** + * Returns the kind of bindings this is. That is one of the kind constants: + * <code>PACKAGE</code>, + * <code>TYPE</code>, + * <code>VARIABLE</code>, + * <code>METHOD</code>, + * <code>ANNOTATION</code>, + * or <code>MEMBER_VALUE_PAIR</code>. + * <p> + * Note that additional kinds might be added in the + * future, so clients should not assume this list is exhaustive and + * should program defensively, e.g. by having a reasonable default + * in a switch statement. + * </p> + * @return one of the kind constants + */ + public int getKind(); + + /** + * Returns the name of this binding. + * Details of the name are specified with each specific kind of binding. + * + * @return the name of this binding + */ + public String getName(); + + /** + * Returns the modifiers for this binding. + * <p> + * Note that deprecated is not included among the modifiers. + * Use <code>isDeprecated</code> to find out whether a binding is deprecated. + * </p> + * + * @return the bit-wise or of <code>Modifier</code> constants + * @see Modifier + */ + public int getModifiers(); + + /** + * Return whether this binding is for something that is deprecated. + * A deprecated class, interface, field, method, or constructor is one that + * is marked with the 'deprecated' tag in its Javadoc comment. + * + * @return <code>true</code> if this binding is deprecated, and + * <code>false</code> otherwise + */ + public boolean isDeprecated(); + + /** + * Return whether this binding is created because the bindings recovery is enabled. This binding is considered + * to be incomplete. Its internal state might be incomplete. + * + * @return <code>true</code> if this binding is a recovered binding, and + * <code>false</code> otherwise + * @since 3.3 + */ + public boolean isRecovered(); + + /** + * Returns whether this binding is synthetic. A synthetic binding is one that + * was made up by the compiler, rather than something declared in the + * source code. Note that default constructors (the 0-argument constructor that + * the compiler generates for class declarations with no explicit constructors + * declarations) are not generally considered synthetic (although they + * may be if the class itself is synthetic). + * But see {@link IMethodBinding#isDefaultConstructor() IMethodBinding.isDefaultConstructor} + * for cases where the compiled-generated default constructor can be recognized + * instead. + * + * @return <code>true</code> if this binding is synthetic, and + * <code>false</code> otherwise + * @see IMethodBinding#isDefaultConstructor() + */ + public boolean isSynthetic(); + + /** + * Returns the Java element that corresponds to this binding. + * Returns <code>null</code> if this binding has no corresponding + * Java element. + * <p> + * For array types, this method returns the Java element that corresponds + * to the array's element type. For raw and parameterized types, this method + * returns the Java element of the erasure. For annotations, this method + * returns the Java element of the annotation (i.e. an {@link IAnnotation}). + * </p> + * <p> + * Here are the cases where a <code>null</code> should be expected: + * <ul> + * <li>primitive types, including void</li> + * <li>null type</li> + * <li>wildcard types</li> + * <li>capture types</li> + * <li>array types of any of the above</li> + * <li>the "length" field of an array type</li> + * <li>the default constructor of a source class</li> + * <li>the constructor of an anonymous class</li> + * <li>member value pairs</li> + * </ul> + * For all other kind of type, method, variable, annotation and package bindings, + * this method returns non-<code>null</code>. + * </p> + * + * @return the Java element that corresponds to this binding, + * or <code>null</code> if none + * @since 3.1 + */ + public IJavaElement getJavaElement(); + + /** + * Returns the key for this binding. + * <p> + * Within a connected cluster of bindings (for example, all bindings + * reachable from a given AST), each binding will have a distinct keys. + * The keys are generated in a manner that is predictable and as + * stable as possible. This last property makes these keys useful for + * comparing bindings between disconnected clusters of bindings (for example, + * the bindings between the "before" and "after" ASTs of the same + * compilation unit). + * </p> + * <p> + * The exact details of how the keys are generated is unspecified. + * However, it is a function of the following information: + * <ul> + * <li>packages - the name of the package (for an unnamed package, + * some internal id)</li> + * <li>classes or interfaces - the VM name of the type and the key + * of its package</li> + * <li>array types - the key of the component type and number of + * dimensions</li> + * <li>primitive types - the name of the primitive type</li> + * <li>fields - the name of the field and the key of its declaring + * type</li> + * <li>methods - the name of the method, the key of its declaring + * type, and the keys of the parameter types</li> + * <li>constructors - the key of its declaring class, and the + * keys of the parameter types</li> + * <li>local variables - the name of the local variable, the index of the + * declaring block relative to its parent, the key of its method</li> + * <li>local types - the name of the type, the index of the declaring + * block relative to its parent, the key of its method</li> + * <li>anonymous types - the occurence count of the anonymous + * type relative to its declaring type, the key of its declaring type</li> + * <li>enum types - treated like classes</li> + * <li>annotation types - treated like interfaces</li> + * <li>type variables - the name of the type variable and + * the key of the generic type or generic method that declares that + * type variable</li> + * <li>wildcard types - the key of the optional wildcard type bound</li> + * <li>capture type bindings - the key of the wildcard captured</li> + * <li>generic type instances - the key of the generic type and the keys + * of the type arguments used to instantiate it, and whether the + * instance is explicit (a parameterized type reference) or + * implicit (a raw type reference)</li> + * <li>generic method instances - the key of the generic method and the keys + * of the type arguments used to instantiate it, and whether the + * instance is explicit (a parameterized method reference) or + * implicit (a raw method reference)</li> + * <li>members of generic type instances - the key of the generic type + * instance and the key of the corresponding member in the generic + * type</li> + * <li>annotations - the key of the annotated element and the key of + * the annotation type</li> + * </ul> + * </p> + * <p>Note that the key for member value pair bindings is + * not yet implemented. This returns <code>null</code> for this kind of bindings.<br> + * Recovered bindings have a unique key. + * </p> + * + * @return the key for this binding + */ + public String getKey(); + + /** + * There is no special definition of equality for bindings; equality is + * simply object identity. Within the context of a single cluster of + * bindings, each binding is represented by a distinct object. However, + * between different clusters of bindings, the binding objects may or may + * not be different; in these cases, the client should compare bindings + * using {@link #isEqualTo(IBinding)}, which checks their keys. + * + * @param obj {@inheritDoc} + * @return {@inheritDoc} + */ + public boolean equals(Object obj); + + /** + * Returns whether this binding has the same key as that of the given + * binding. Within the context of a single cluster of bindings, each + * binding is represented by a distinct object. However, between + * different clusters of bindings, the binding objects may or may + * not be different objects; in these cases, the binding keys + * are used where available. + * + * @param binding the other binding, or <code>null</code> + * @return <code>true</code> if the given binding is the identical + * object as this binding, or if the keys of both bindings are the + * same string; <code>false</code> if the given binding is + * <code>null</code>, or if the bindings do not have the same key, + * or if one or both of the bindings have no key + * @see #getKey() + * @since 3.1 + */ + public boolean isEqualTo(IBinding binding); + + /** + * Returns a string representation of this binding suitable for debugging + * purposes only. + * + * @return a debug string + */ + public String toString(); +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IDocElement.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IDocElement.java new file mode 100644 index 000000000..d492a90a2 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IDocElement.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +/** + * Internal marker-type interface used to tag node types that can legitimately + * be included in {@link TagElement#fragments() TagElement.fragments()}. + * + * @since 3.0 + */ +interface IDocElement { + // marker-type interfaces have no members +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IExtendedModifier.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IExtendedModifier.java new file mode 100644 index 000000000..50b831cf3 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IExtendedModifier.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2004, 2009 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.dom; + +/** + * Common interface for AST nodes that represent modifiers or + * annotations. + * <pre> + * ExtendedModifier: + * Modifier + * Annotation + * </pre> + * @since 3.1 + */ +public interface IExtendedModifier { + + /** + * Returns whether this extended modifier is a standard modifier. + * + * @return <code>true</code> if this is a standard modifier + * (instance of {@link Modifier}), and <code>false</code> otherwise + */ + public boolean isModifier(); + + /** + * Returns whether this extended modifier is an annotation. + * + * @return <code>true</code> if this is an annotation + * (instance of a subclass of {@link Annotation}), and + * <code>false</code> otherwise + */ + public boolean isAnnotation(); +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IMemberValuePairBinding.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IMemberValuePairBinding.java new file mode 100644 index 000000000..1d8fb5183 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IMemberValuePairBinding.java @@ -0,0 +1,59 @@ +/******************************************************************************* + * Copyright (c) 2005, 2008 BEA Systems, Inc. + * 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: + * tyeung@bea.com - initial API and implementation + * IBM Corporation - changed interface to extend IBinding + * IBM Corporation - renamed from IResolvedMemberValuePair to IMemberValuePairBinding + *******************************************************************************/ +package org.eclipse.jdt.core.dom; + +/** + * Represents a resolved instance of an annotation's member value pair. + * Resolved annotation are computed along with other bindings; these objects + * correspond to {@link MemberValuePair} nodes. + * + * @since 3.2 + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface IMemberValuePairBinding extends IBinding { +/** + * Returns the name of the annotation type member. + * + * @return the name of the member + */ +public String getName(); + +/** + * Returns the method binding corresponding to the named annotation type member. + * + * @return the method binding for the annotation type member + */ +public IMethodBinding getMethodBinding(); + +/** + * Returns the resolved value. Resolved values are represented as follows: + * <ul> + * <li>Primitive type - the equivalent boxed object</li> + * <li>java.lang.Class - the <code>ITypeBinding</code> for the class object</li> + * <li>java.lang.String - the string value itself</li> + * <li>enum type - the <code>IVariableBinding</code> for the enum constant</li> + * <li>annotation type - an <code>IAnnotationBinding</code></li> + * <li>array type - an <code>Object[]</code> whose elements are as per above + * (the language only allows single dimensional arrays in annotations)</li> + * </ul> + * + * @return the resolved value, or <code>null</code> if none exists + */ +public Object getValue(); + +/** + * @return <code>true</code> iff this member value pair's value is the default value. + * Returns <code>false</code> otherwise. + */ +public boolean isDefault(); +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IMethodBinding.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IMethodBinding.java new file mode 100644 index 000000000..e6ee64fc6 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IMethodBinding.java @@ -0,0 +1,334 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + * Technical University Berlin - extended API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +/** + * A method binding represents a method or constructor of a class or interface. + * Method bindings usually correspond directly to method or + * constructor declarations found in the source code. + * However, in certain cases of references to a generic method, + * the method binding may correspond to a copy of a generic method + * declaration with substitutions for the method's type parameters + * (for these, <code>getTypeArguments</code> returns a non-empty + * list, and either <code>isParameterizedMethod</code> or + * <code>isRawMethod</code> returns <code>true</code>). + * And in certain cases of references to a method declared in a + * generic type, the method binding may correspond to a copy of a + * method declaration with substitutions for the type's type + * parameters (for these, <code>getTypeArguments</code> returns + * an empty list, and both <code>isParameterizedMethod</code> and + * <code>isRawMethod</code> return <code>false</code>). + * + * @see ITypeBinding#getDeclaredMethods() + * @since 2.0 + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface IMethodBinding extends IBinding { + + /** + * Returns whether this binding is for a constructor or a method. + * + * @return <code>true</code> if this is the binding for a constructor, + * and <code>false</code> if this is the binding for a method + */ + public boolean isConstructor(); + + /** + * Returns whether this binding is known to be a compiler-generated + * default constructor. + * <p> + * This method returns <code>false</code> for: + * <ul> + * <li>methods</li> + * <li>constructors with more than one parameter</li> + * <li>0-argument constructors where the binding information was obtained + * from a Java source file containing an explicit 0-argument constructor + * declaration</li> + * <li>0-argument constructors where the binding information was obtained + * from a Java class file (it is not possible to determine from a + * class file whether a 0-argument constructor was present in the source + * code versus generated automatically by a Java compiler)</li> + * </ul> + * + * @return <code>true</code> if this is known to be the binding for a + * compiler-generated default constructor, and <code>false</code> + * otherwise + * @since 3.0 + */ + public boolean isDefaultConstructor(); + + /** + * Returns the name of the method declared in this binding. The method name + * is always a simple identifier. The name of a constructor is always the + * same as the declared name of its declaring class. + * + * @return the name of this method, or the declared name of this + * constructor's declaring class + */ + public String getName(); + + /** + * Returns the type binding representing the class or interface + * that declares this method or constructor. + * + * @return the binding of the class or interface that declares this method + * or constructor + */ + public ITypeBinding getDeclaringClass(); + + /** + * Returns the resolved default value of an annotation type member, + * or <code>null</code> if the member has no default value, or if this + * is not the binding for an annotation type member. + * <p> + * Resolved values are represented as follows (same as for + * {@link IMemberValuePairBinding#getValue()}): + * <ul> + * <li>Primitive type - the equivalent boxed object</li> + * <li>java.lang.Class - the <code>ITypeBinding</code> for the class object</li> + * <li>java.lang.String - the string value itself</li> + * <li>enum type - the <code>IVariableBinding</code> for the enum constant</li> + * <li>annotation type - an <code>IAnnotationBinding</code></li> + * <li>array type - an <code>Object[]</code> whose elements are as per above + * (the language only allows single dimensional arrays in annotations)</li> + * </ul> + * + * @return the default value of this annotation type member, or <code>null</code> + * if none or not applicable + * @since 3.2 + */ + public Object getDefaultValue(); + + /** + * Returns the resolved annotations of a parameter of this method. + * The result returned is the same regardless of whether + * this is a parameterized method. + * + * @param paramIndex the index of the parameter of interest + * @return the resolved annotations of the <code>paramIndex</code>th parameter, + * or an empty list if there are none + * @throws ArrayIndexOutOfBoundsException if <code>paramIndex</code> is + * not a valid index + * @since 3.2 + */ + public IAnnotationBinding[] getParameterAnnotations(int paramIndex); + + /** + * Returns a list of type bindings representing the formal parameter types, + * in declaration order, of this method or constructor. Returns an array of + * length 0 if this method or constructor does not takes any parameters. + * <p> + * Note that the binding for the last parameter type of a vararg method + * declaration like <code>void fun(Foo... args)</code> is always for + * an array type (i.e., <code>Foo[]</code>) reflecting the the way varargs + * get compiled. However, the type binding obtained directly from + * the <code>SingleVariableDeclaration</code> for the vararg parameter + * is always for the type as written; i.e., the type binding for + * <code>Foo</code>. + * </p> + * <p> + * Note: The result does not include synthetic parameters introduced by + * inner class emulation. + * </p> + * + * @return a (possibly empty) list of type bindings for the formal + * parameters of this method or constructor + */ + public ITypeBinding[] getParameterTypes(); + + /** + * Returns the binding for the return type of this method. Returns the + * special primitive <code>void</code> return type for constructors. + * + * @return the binding for the return type of this method, or the + * <code>void</code> return type for constructors + */ + public ITypeBinding getReturnType(); + + /** + * Returns a list of type bindings representing the types of the exceptions thrown + * by this method or constructor. Returns an array of length 0 if this method + * throws no exceptions. The resulting types are in no particular order. + * + * @return a list of type bindings for exceptions + * thrown by this method or constructor + */ + public ITypeBinding[] getExceptionTypes(); + + /** + * Returns the type parameters of this method or constructor binding. + * <p> + * Note that type parameters only occur on the binding of the + * declaring generic method. Type bindings corresponding to a raw or + * parameterized reference to a generic method do not carry type + * parameters (they instead have non-empty type arguments + * and non-trivial erasure). + * </p> + * + * @return the list of binding for the type variables for the type + * parameters of this method, or otherwise the empty list + * @see ITypeBinding#isTypeVariable() + * @since 3.1 + */ + public ITypeBinding[] getTypeParameters(); + + /** + * Returns whether this is the binding for an annotation type member. + * + * @return <code>true</code> iff this is the binding for an annotation type member + * and <code>false</code> otherwise + * @since 3.2 + */ + public boolean isAnnotationMember(); + + /** + * Returns whether this method binding represents a declaration of + * a generic method. + * <p> + * Note that type parameters only occur on the binding of the + * declaring generic method; e.g., <code>public <T> T identity(T t);</code>. + * Method bindings corresponding to a raw or parameterized reference to a generic + * method do not carry type parameters (they instead have non-empty type arguments + * and non-trivial erasure). + * This method is fully equivalent to <code>getTypeParameters().length > 0)</code>. + * </p> + * <p> + * Note that {@link #isGenericMethod()}, + * {@link #isParameterizedMethod()}, + * and {@link #isRawMethod()} are mutually exclusive. + * </p> + * + * @return <code>true</code> if this method binding represents a + * declaration of a generic method, and <code>false</code> otherwise + * @see #getTypeParameters() + * @since 3.1 + */ + public boolean isGenericMethod(); + + /** + * Returns whether this method binding represents an instance of + * a generic method corresponding to a parameterized method reference. + * <p> + * Note that {@link #isGenericMethod()}, + * {@link #isParameterizedMethod()}, + * and {@link #isRawMethod()} are mutually exclusive. + * </p> + * + * @return <code>true</code> if this method binding represents a + * an instance of a generic method corresponding to a parameterized + * method reference, and <code>false</code> otherwise + * @see #getMethodDeclaration() + * @see #getTypeArguments() + * @since 3.1 + */ + public boolean isParameterizedMethod(); + + /** + * Returns the type arguments of this generic method instance, or the + * empty list for other method bindings. + * <p> + * Note that type arguments only occur on a method binding that represents + * an instance of a generic method corresponding to a raw or parameterized + * reference to a generic method. Do not confuse these with type parameters + * which only occur on the method binding corresponding directly to the + * declaration of a generic method. + * </p> + * + * @return the list of type bindings for the type arguments used to + * instantiate the corrresponding generic method, or otherwise the empty list + * @see #getMethodDeclaration() + * @see #isParameterizedMethod() + * @see #isRawMethod() + * @since 3.1 + */ + public ITypeBinding[] getTypeArguments(); + + /** + * Returns the binding for the method declaration corresponding to this + * method binding. For parameterized methods ({@link #isParameterizedMethod()}) + * and raw methods ({@link #isRawMethod()}), this method returns the binding + * for the corresponding generic method. For other method bindings, this + * returns the same binding. + * + * <p>Note: The one notable exception is the method <code>Object.getClass()</code>, + * which is declared to return <code>Class<? extends Object></code>, but + * when invoked its return type becomes <code>Class<? extends + * </code><em>R</em><code>></code>, where <em>R</em> is the compile type of + * the receiver of the method invocation.</p> + * + * @return the method binding + * @since 3.1 + */ + public IMethodBinding getMethodDeclaration(); + + /** + * Returns whether this method binding represents an instance of + * a generic method corresponding to a raw method reference. + * <p> + * Note that {@link #isGenericMethod()}, + * {@link #isParameterizedMethod()}, + * and {@link #isRawMethod()} are mutually exclusive. + * </p> + * + * @return <code>true</code> if this method binding represents a + * an instance of a generic method corresponding to a raw + * method reference, and <code>false</code> otherwise + * @see #getMethodDeclaration() + * @see #getTypeArguments() + * @since 3.1 + */ + public boolean isRawMethod(); + + /** + * Returns whether this method's signature is a subsignature of the given method as + * specified in section 8.4.2 of <em>The Java Language Specification, Third Edition</em> (JLS3). + * + * @return <code>true</code> if this method's signature is a subsignature of the given method + * @since 3.1 + */ + public boolean isSubsignature(IMethodBinding otherMethod); + + /** + * Returns whether this is a variable arity method. + * <p> + * Note: Variable arity ("varargs") methods were added in JLS3. + * </p> + * + * @return <code>true</code> if this is a variable arity method, + * and <code>false</code> otherwise + * @since 3.1 + */ + public boolean isVarargs(); + + /** + * Returns whether this method overrides the given method, + * as specified in section 8.4.8.1 of <em>The Java Language + * Specification, Third Edition</em> (JLS3). + * + * @param method the method that is possibly overriden + * @return <code>true</code> if this method overrides the given method, + * and <code>false</code> otherwise + * @since 3.1 + */ + public boolean overrides(IMethodBinding method); + +//{ObjectTeams: + /** + * Is method copied due to implicit inheritance? + * (beware: copied methods don't have a java element.) + * + * @since OTDT 1.1.3 + */ + public boolean isCopied(); +// SH} +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IMethodMappingBinding.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IMethodMappingBinding.java new file mode 100644 index 000000000..d354b2a4f --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IMethodMappingBinding.java @@ -0,0 +1,60 @@ +/********************************************************************** + * This file is part of "Object Teams Development Tooling"-Software + * + * Copyright 2005, 2007 Fraunhofer Gesellschaft, Munich, Germany, + * for its Fraunhofer Institute for Computer Architecture and Software + * Technology (FIRST), Berlin, Germany and Technical University Berlin, + * Germany. + * + * 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 + * $Id: IMethodMappingBinding.java 23417 2010-02-03 20:13:55Z stephan $ + * + * Please visit http://www.eclipse.org/objectteams for updates and contact. + * + * Contributors: + * Fraunhofer FIRST - Initial API and implementation + * Technical University Berlin - Initial API and implementation + **********************************************************************/ +package org.eclipse.jdt.core.dom; + +import org.eclipse.objectteams.otdt.core.compiler.InferenceKind; + +/** + * A callin/callout binding represents a callin-/callout method mapping + * or a callout to field. + * + * @author mkr + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface IMethodMappingBinding extends IBinding +{ + + public String getName(); + + /** + * Returns the type binding representing the role class + * that declares this callin-/callout mapping. + * + * @return the binding of the role class that declares this mapping + */ + public ITypeBinding getDeclaringRoleClass(); + + public ITypeBinding getReferencedBaseClass(); + + public IMethodBinding getRoleMethod(); + + public IMethodBinding[] getBaseMethods(); + + public String[] getBaseArgumentNames(); + + /** + * @return true if this is a callin binding (vs. callout) + */ + public boolean isCallin(); + + /** Is this mapping an inferred callout? Which kind? */ + public InferenceKind getInferenceKind(); +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IPackageBinding.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IPackageBinding.java new file mode 100644 index 000000000..8f3c7aa87 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IPackageBinding.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +/** + * A package binding represents a named or unnamed package. + * + * @since 2.0 + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface IPackageBinding extends IBinding { + + /** + * Returns the name of the package represented by this binding. For named + * packages, this is the fully qualified package name (using "." for + * separators). For unnamed packages, this is an empty string. + * + * @return the name of the package represented by this binding, or + * an empty string for an unnamed package + */ + public String getName(); + + /** + * Returns whether this package is an unnamed package. + * See <em>The Java Language Specification</em> section 7.4.2 for details. + * + * @return <code>true</code> if this is an unnamed package, and + * <code>false</code> otherwise + */ + public boolean isUnnamed(); + + /** + * Returns the list of name component making up the name of the package + * represented by this binding. For example, for the package named + * "com.example.tool", this method returns {"com", "example", "tool"}. + * Returns the empty list for unnamed packages. + * + * @return the name of the package represented by this binding, or the + * empty list for unnamed packages + */ + public String[] getNameComponents(); + +// /** +// * Finds and returns the binding for the class or interface with the given +// * name declared in this package. +// * <p> +// * For top-level classes and interfaces, the name here is just the simple +// * name of the class or interface. For nested classes and interfaces, the +// * name is the VM class name (in other words, a name like +// * <code>"Outer$Inner"</code> as used to name the class file; see +// * <code>ITypeBinding.getName</code>). +// * </p> +// * +// * @param name the name of a class or interface +// * @return the type binding for the class or interface with the +// * given name declared in this package, or <code>null</code> +// * if there is no such type +// */ +// public ITypeBinding findTypeBinding(String name); +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ITypeBinding.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ITypeBinding.java new file mode 100644 index 000000000..c5d8b48a3 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ITypeBinding.java @@ -0,0 +1,1041 @@ +/******************************************************************************* + * Copyright (c) 2000, 2009 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 + * $Id: ITypeBinding.java 21855 2009-07-14 18:55:31Z stephan $ + * + * Contributors: + * IBM Corporation - initial API and implementation + * Fraunhofer FIRST - extended API and implementation + * Technical University Berlin - extended API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + + +/** + * MIGRATION_STATE: 3.4 + * + * <h4>OTDT changes:</h4> + * <dl> + * <dt>What:<dd> new lookup functions for teams and roles. + * </dl> + * <hr> + * A type binding represents fully-resolved type. There are a number of + * different kinds of type bindings: + * <ul> + * <li>a class - represents the class declaration; + * possibly with type parameters</li> + * <li>an interface - represents the class declaration; + * possibly with type parameters</li> + * <li>an enum - represents the enum declaration (enum types do not have + * have type parameters)</li> + * <li>an annotation - represents the annotation type declaration + * (annotation types do not have have type parameters)</li> + * <li>an array type - array types are referenced but not explicitly + * declared</li> + * <li>a primitive type (including the special return type <code>void</code>) + * - primitive types are referenced but not explicitly declared</li> + * <li>the null type - this is the special type of <code>null</code></li> + * <li>a type variable - represents the declaration of a type variable; + * possibly with type bounds</li> + * <li>a wildcard type - represents a wild card used as a type argument in + * a parameterized type reference</li> + * <li>a raw type - represents a legacy non-parameterized reference to + * a generic type</li> + * <li>a parameterized type - represents an copy of a type declaration + * with substitutions for its type parameters</li> + * <li>a capture - represents a capture binding</li> + * </ul> + * + * @see ITypeBinding#getDeclaredTypes() + * @since 2.0 + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface ITypeBinding extends IBinding { + + + /** + * Answer an array type binding using the receiver and the given dimension. + * + * <p>If the receiver is an array binding, then the resulting dimension is the given dimension + * plus the dimension of the receiver. Otherwise the resulting dimension is the given + * dimension.</p> + * + * @param dimension the given dimension + * @return an array type binding + * @throws IllegalArgumentException:<ul> + * <li>if the receiver represents the void type</li> + * <li>if the resulting dimensions is lower than one or greater than 255</li> + * </ul> + * @since 3.3 + */ + public ITypeBinding createArrayType(int dimension); + + /** + * Returns the binary name of this type binding. + * The binary name of a class is defined in the Java Language + * Specification 3rd edition, section 13.1. + * <p> + * Note that in some cases, the binary name may be unavailable. + * This may happen, for example, for a local type declared in + * unreachable code. + * </p> + * + * @return the binary name of this type, or <code>null</code> + * if the binary name is unknown + * @since 3.0 + */ + public String getBinaryName(); + + /** + * Returns the bound of this wildcard type if it has one. + * Returns <code>null</code> if this is not a wildcard type. + * + * @return the bound of this wildcard type, or <code>null</code> if none + * @see #isWildcardType() + * @see #isUpperbound() + * @since 3.1 + */ + public ITypeBinding getBound(); + + /** + * Returns the generic type associated with this wildcard type, if it has one. + * Returns <code>null</code> if this is not a wildcard type. + * + * @return the generic type associated with this wildcard type, or <code>null</code> if none + * @see #isWildcardType() + * @since 3.5 + */ + public ITypeBinding getGenericTypeOfWildcardType(); + + /** + * Returns the rank associated with this wildcard type. The rank of this wild card type is the relative + * position of the wild card type in the parameterization of the associated generic type. + * Returns <code>-1</code> if this is not a wildcard type. + * + * @return the rank associated with this wildcard type, or <code>-1</code> if none + * @see #isWildcardType() + * @since 3.5 + */ + public int getRank(); + + /** + * Returns the binding representing the component type of this array type, + * or <code>null</code> if this is not an array type binding. The component + * type of an array might be an array type. + * <p>This is subject to change before 3.2 release.</p> + * + * @return the component type binding, or <code>null</code> if this is + * not an array type + * @since 3.2 + */ + public ITypeBinding getComponentType(); + + /** + * Returns a list of bindings representing all the fields declared + * as members of this class, interface, or enum type. + * + * <p>These include public, protected, default (package-private) access, + * and private fields declared by the class, but excludes inherited fields. + * Synthetic fields may or may not be included. Fields from binary types that + * reference unresolvable types may not be included.</p> + * + * <p>Returns an empty list if the class, interface, or enum declares no fields, + * and for other kinds of type bindings that do not directly have members.</p> + * + * <p>The resulting bindings are in no particular order.</p> + * + * @return the list of bindings for the field members of this type, + * or the empty list if this type does not have field members + */ + public IVariableBinding[] getDeclaredFields(); + + /** + * Returns a list of method bindings representing all the methods and + * constructors declared for this class, interface, enum, or annotation + * type. + * <p>These include public, protected, default (package-private) access, + * and private methods Synthetic methods and constructors may or may not be + * included. Returns an empty list if the class, interface, or enum, + * type declares no methods or constructors, if the annotation type declares + * no members, or if this type binding represents some other kind of type + * binding. Methods from binary types that reference unresolvable types may + * not be included.</p> + * <p>The resulting bindings are in no particular order.</p> + * + * @return the list of method bindings for the methods and constructors + * declared by this class, interface, enum type, or annotation type, + * or the empty list if this type does not declare any methods or constructors + */ + public IMethodBinding[] getDeclaredMethods(); + +//{ObjecgtTeams: + IMethodMappingBinding[] getResolvedMethodMappings(); +// SH} + /** + * Returns the declared modifiers for this class or interface binding + * as specified in the original source declaration of the class or + * interface. The result may not correspond to the modifiers in the compiled + * binary, since the compiler may change them (in particular, for inner + * class emulation). The <code>getModifiers</code> method should be used if + * the compiled modifiers are needed. Returns -1 if this type does not + * represent a class or interface. + * + * @return the bit-wise or of <code>Modifier</code> constants + * @see #getModifiers() + * @see Modifier + */ + public int getDeclaredModifiers(); + + /** + * Returns a list of type bindings representing all the types declared as + * members of this class, interface, or enum type. + * These include public, protected, default (package-private) access, + * and private classes, interfaces, enum types, and annotation types + * declared by the type, but excludes inherited types. Returns an empty + * list if the type declares no type members, or if this type + * binding represents an array type, a primitive type, a type variable, + * a wildcard type, a capture, or the null type. + * The resulting bindings are in no particular order. + * + * @return the list of type bindings for the member types of this type, + * or the empty list if this type does not have member types + */ + public ITypeBinding[] getDeclaredTypes(); + + /** + * Returns the type binding representing the class, interface, or enum + * that declares this binding. + * <p> + * The declaring class of a member class, interface, enum, annotation + * type is the class, interface, or enum type of which it is a member. + * The declaring class of a local class or interface (including anonymous + * classes) is the innermost class or interface containing the expression + * or statement in which this type is declared. + * </p> + * <p>The declaring class of a type variable is the class in which the type + * variable is declared if it is declared on a type. It returns + * <code>null</code> otherwise. + * </p> + * <p>The declaring class of a capture binding is the innermost class or + * interface containing the expression or statement in which this capture is + * declared. + * </p> + * <p>Array types, primitive types, the null type, top-level types, + * wildcard types, recovered binding have no declaring class. + * </p> + * + * @return the binding of the type that declares this type, or + * <code>null</code> if none + */ + public ITypeBinding getDeclaringClass(); + + /** + * Returns the method binding representing the method that declares this binding + * of a local type or type variable. + * <p> + * The declaring method of a local class or interface (including anonymous + * classes) is the innermost method containing the expression or statement in + * which this type is declared. Returns <code>null</code> if the type + * is declared in an initializer. + * </p> + * <p> + * The declaring method of a type variable is the method in which the type + * variable is declared if it is declared on a method. It + * returns <code>null</code> otherwise. + * </p> + * <p>Array types, primitive types, the null type, top-level types, + * wildcard types, capture bindings, and recovered binding have no + * declaring method. + * </p> + * + * @return the binding of the method that declares this type, or + * <code>null</code> if none + * @since 3.1 + */ + public IMethodBinding getDeclaringMethod(); + + /** + * Returns the dimensionality of this array type, or <code>0</code> if this + * is not an array type binding. + * + * @return the number of dimension of this array type binding, or + * <code>0</code> if this is not an array type + */ + public int getDimensions(); + + /** + * Returns the binding representing the element type of this array type, + * or <code>null</code> if this is not an array type binding. The element + * type of an array is never itself an array type. + * + * @return the element type binding, or <code>null</code> if this is + * not an array type + */ + public ITypeBinding getElementType(); + + /** + * Returns the erasure of this type binding. + * <ul> + * <li>For parameterized types ({@link #isParameterizedType()}) + * - returns the binding for the corresponding generic type.</li> + * <li>For raw types ({@link #isRawType()}) + * - returns the binding for the corresponding generic type.</li> + * <li>For wildcard types ({@link #isWildcardType()}) + * - returns the binding for the upper bound if it has one and + * java.lang.Object in other cases.</li> + * <li>For type variables ({@link #isTypeVariable()}) + * - returns the binding for the erasure of the leftmost bound + * if it has bounds and java.lang.Object if it does not.</li> + * <li>For captures ({@link #isCapture()}) + * - returns the binding for the erasure of the leftmost bound + * if it has bounds and java.lang.Object if it does not.</li> + * <li>For array types ({@link #isArray()}) - returns an array type of + * the same dimension ({@link #getDimensions()}) as this type + * binding for which the element type is the erasure of the element type + * ({@link #getElementType()}) of this type binding.</li> + * <li>For all other type bindings - returns the identical binding.</li> + * </ul> + * + * @return the erasure type binding + * @since 3.1 + */ + public ITypeBinding getErasure(); + + /** + * Returns a list of type bindings representing the direct superinterfaces + * of the class, interface, or enum type represented by this type binding. + * <p> + * If this type binding represents a class or enum type, the return value + * is an array containing type bindings representing all interfaces + * directly implemented by this class. The number and order of the interface + * objects in the array corresponds to the number and order of the interface + * names in the <code>implements</code> clause of the original declaration + * of this type. + * </p> + * <p> + * If this type binding represents an interface, the array contains + * type bindings representing all interfaces directly extended by this + * interface. The number and order of the interface objects in the array + * corresponds to the number and order of the interface names in the + * <code>extends</code> clause of the original declaration of this interface. + * </p> + * <p> + * If the class or enum implements no interfaces, or the interface extends + * no interfaces, or if this type binding represents an array type, a + * primitive type, the null type, a type variable, an annotation type, + * a wildcard type, or a capture binding, this method returns an array of + * length 0. + * </p> + * + * @return the list of type bindings for the interfaces extended by this + * class or enum, or interfaces extended by this interface, or otherwise + * the empty list + */ + public ITypeBinding[] getInterfaces(); + + /** + * Returns the compiled modifiers for this class, interface, enum, + * or annotation type binding. + * The result may not correspond to the modifiers as declared in the + * original source, since the compiler may change them (in particular, + * for inner class emulation). The <code>getDeclaredModifiers</code> method + * should be used if the original modifiers are needed. + * Returns 0 if this type does not represent a class, an interface, an enum, an annotation + * type or a recovered type. + * + * @return the compiled modifiers for this type binding or 0 + * if this type does not represent a class, an interface, an enum, an annotation + * type or a recovered type. + * @see #getDeclaredModifiers() + */ + public int getModifiers(); + + /** + * Returns the unqualified name of the type represented by this binding + * if it has one. + * <ul> + * <li>For top-level types, member types, and local types, + * the name is the simple name of the type. + * Example: <code>"String"</code> or <code>"Collection"</code>. + * Note that the type parameters of a generic type are not included.</li> + * <li>For primitive types, the name is the keyword for the primitive type. + * Example: <code>"int"</code>.</li> + * <li>For the null type, the name is the string "null".</li> + * <li>For anonymous classes, which do not have a name, + * this method returns an empty string.</li> + * <li>For array types, the name is the unqualified name of the component + * type (as computed by this method) followed by "[]". + * Example: <code>"String[]"</code>. Note that the component type is never an + * an anonymous class.</li> + * <li>For type variables, the name is just the simple name of the + * type variable (type bounds are not included). + * Example: <code>"X"</code>.</li> + * <li>For type bindings that correspond to particular instances of a generic + * type arising from a parameterized type reference, + * the name is the unqualified name of the erasure type (as computed by this method) + * followed by the names (again, as computed by this method) of the type arguments + * surrounded by "<>" and separated by ",". + * Example: <code>"Collection<String>"</code>. + * </li> + * <li>For type bindings that correspond to particular instances of a generic + * type arising from a raw type reference, the name is the unqualified name of + * the erasure type (as computed by this method). + * Example: <code>"Collection"</code>.</li> + * <li>For wildcard types, the name is "?" optionally followed by + * a single space followed by the keyword "extends" or "super" + * followed a single space followed by the name of the bound (as computed by + * this method) when present. + * Example: <code>"? extends InputStream"</code>. + * </li> + * <li>Capture types do not have a name. For these types, + * and array types thereof, this method returns an empty string.</li> + * </ul> + * + * @return the unqualified name of the type represented by this binding, + * or the empty string if it has none + * @see #getQualifiedName() + */ + public String getName(); + + /** + * Returns the binding for the package in which this type is declared. + * + * <p>The package of a recovered type reference binding is either + * the package of the enclosing type, or, if the type name is the name of a + * {@linkplain AST#resolveWellKnownType(String) well-known type}, + * the package of the matching well-known type.</p> + * + * @return the binding for the package in which this class, interface, + * enum, or annotation type is declared, or <code>null</code> if this type + * binding represents a primitive type, an array type, the null type, + * a type variable, a wildcard type, a capture binding. + */ + public IPackageBinding getPackage(); + + /** + * Returns the fully qualified name of the type represented by this + * binding if it has one. + * <ul> + * <li>For top-level types, the fully qualified name is the simple name of + * the type preceded by the package name (or unqualified if in a default package) + * and a ".". + * Example: <code>"java.lang.String"</code> or <code>"java.util.Collection"</code>. + * Note that the type parameters of a generic type are not included.</li> + * <li>For members of top-level types, the fully qualified name is the + * simple name of the type preceded by the fully qualified name of the + * enclosing type (as computed by this method) and a ".". + * Example: <code>"java.io.ObjectInputStream.GetField"</code>. + * If the binding is for a member type that corresponds to a particular instance + * of a generic type arising from a parameterized type reference, the simple + * name of the type is followed by the fully qualified names of the type arguments + * (as computed by this method) surrounded by "<>" and separated by ",". + * Example: <code>"pkg.Outer.Inner<java.lang.String>"</code>. + * </li> + * <li>For primitive types, the fully qualified name is the keyword for + * the primitive type. + * Example: <code>"int"</code>.</li> + * <li>For the null type, the fully qualified name is the string + * "null".</li> + * <li>Local types (including anonymous classes) and members of local + * types do not have a fully qualified name. For these types, and array + * types thereof, this method returns an empty string.</li> + * <li>For array types whose component type has a fully qualified name, + * the fully qualified name is the fully qualified name of the component + * type (as computed by this method) followed by "[]". + * Example: <code>"java.lang.String[]"</code>.</li> + * <li>For type variables, the fully qualified name is just the name of the + * type variable (type bounds are not included). + * Example: <code>"X"</code>.</li> + * <li>For type bindings that correspond to particular instances of a generic + * type arising from a parameterized type reference, + * the fully qualified name is the fully qualified name of the erasure + * type followed by the fully qualified names of the type arguments surrounded by "<>" and separated by ",". + * Example: <code>"java.util.Collection<java.lang.String>"</code>. + * </li> + * <li>For type bindings that correspond to particular instances of a generic + * type arising from a raw type reference, + * the fully qualified name is the fully qualified name of the erasure type. + * Example: <code>"java.util.Collection"</code>. Note that the + * the type parameters are omitted.</li> + * <li>For wildcard types, the fully qualified name is "?" optionally followed by + * a single space followed by the keyword "extends" or "super" + * followed a single space followed by the fully qualified name of the bound + * (as computed by this method) when present. + * Example: <code>"? extends java.io.InputStream"</code>. + * </li> + * <li>Capture types do not have a fully qualified name. For these types, + * and array types thereof, this method returns an empty string.</li> + * </ul> + * + * @return the fully qualified name of the type represented by this + * binding, or the empty string if it has none + * @see #getName() + * @since 2.1 + */ + public String getQualifiedName(); + + /** + * Returns the type binding for the superclass of the type represented + * by this class binding. + * <p> + * If this type binding represents any class other than the class + * <code>java.lang.Object</code>, then the type binding for the direct + * superclass of this class is returned. If this type binding represents + * the class <code>java.lang.Object</code>, then <code>null</code> is + * returned. + * <p> + * Loops that ascend the class hierarchy need a suitable termination test. + * Rather than test the superclass for <code>null</code>, it is more + * transparent to check whether the class is <code>Object</code>, by + * comparing whether the class binding is identical to + * <code>ast.resolveWellKnownType("java.lang.Object")</code>. + * </p> + * <p> + * If this type binding represents an interface, an array type, a + * primitive type, the null type, a type variable, an enum type, + * an annotation type, a wildcard type, or a capture binding then + * <code>null</code> is returned. + * </p> + * + * @return the superclass of the class represented by this type binding, + * or <code>null</code> if none + * @see AST#resolveWellKnownType(String) + */ + public ITypeBinding getSuperclass(); + + /** + * Returns the type arguments of this generic type instance, or the + * empty list for other type bindings. + * <p> + * Note that type arguments only occur on a type binding that represents + * an instance of a generic type corresponding to a parameterized type + * reference (e.g., <code>Collection<String></code>). + * Do not confuse these with type parameters which only occur on the + * type binding corresponding directly to the declaration of the + * generic class or interface (e.g., <code>Collection<T></code>). + * </p> + * + * @return the list of type bindings for the type arguments used to + * instantiate the corresponding generic type, or otherwise the empty list + * @see #getTypeDeclaration() + * @see #isGenericType() + * @see #isParameterizedType() + * @see #isRawType() + * @since 3.1 + */ + public ITypeBinding[] getTypeArguments(); + + /** + * Returns the declared type bounds of this type variable or capture. If the + * variable or the capture had no explicit bound, then it returns an empty list. + * <p> + * Note that per construction, it can only contain one class or array type, + * at most, and then it is located in first position. + * </p> + * <p> + * Also note that array type bound may only occur in the case of a capture + * binding, e.g. <code>capture-of ? extends Object[]</code> + * </p> + * + * @return the list of type bindings for this type variable or capture, + * or otherwise the empty list + * @see #isCapture() + * @see #isTypeVariable() + * @since 3.1 + */ + public ITypeBinding[] getTypeBounds(); + + /** + * Returns the binding for the type declaration corresponding to this type + * binding. + * <p>For parameterized types ({@link #isParameterizedType()}) + * and most raw types ({@link #isRawType()}), this method returns the binding + * for the corresponding generic type.</p> + * <p>For raw member types ({@link #isRawType()}, {@link #isMember()}) + * of a raw declaring class, the type declaration is a generic or a non-generic + * type.</p> + * <p>A different non-generic binding will be returned when one of the declaring + * types/methods was parameterized.</p> + * <p>For other type bindings, this returns the same binding.</p> + * + * @return the type binding + * @since 3.1 + */ + public ITypeBinding getTypeDeclaration(); + + /** + * Returns the type parameters of this class or interface type binding. + * <p> + * Note that type parameters only occur on the binding of the + * declaring generic class or interface; e.g., <code>Collection<T></code>. + * Type bindings corresponding to a raw or parameterized reference to a generic + * type do not carry type parameters (they instead have non-empty type arguments + * and non-trivial erasure). + * </p> + * + * @return the list of binding for the type variables for the type + * parameters of this type, or otherwise the empty list + * @see #isTypeVariable() + * @since 3.1 + */ + // TODO (jeem) - clarify whether binding for a generic type instance carries a copy of the generic type's type parameters as well as type arguments + public ITypeBinding[] getTypeParameters(); + + /** + * Returns the corresponding wildcard binding of this capture binding. + * Returns <code>null</code> if this type bindings does not represent + * a capture binding. + * + * @return the corresponding wildcard binding for a capture + * binding, <code>null</code> otherwise + * @since 3.1 + */ + public ITypeBinding getWildcard(); + + /** + * Returns whether this type binding represents an annotation type. + * <p> + * Note that an annotation type is always an interface. + * </p> + * + * @return <code>true</code> if this object represents an annotation type, + * and <code>false</code> otherwise + * @since 3.1 + */ + public boolean isAnnotation(); + + /** + * Returns whether this type binding represents an anonymous class. + * <p> + * An anonymous class is a subspecies of local class, and therefore mutually + * exclusive with member types. Note that anonymous classes have no name + * (<code>getName</code> returns the empty string). + * </p> + * + * @return <code>true</code> if this type binding is for an anonymous class, + * and <code>false</code> otherwise + */ + public boolean isAnonymous(); + + /** + * Returns whether this type binding represents an array type. + * + * @return <code>true</code> if this type binding is for an array type, + * and <code>false</code> otherwise + * @see #getElementType() + * @see #getDimensions() + */ + public boolean isArray(); + + /** + * Returns whether an expression of this type can be assigned to a variable + * of the given type, as specified in section 5.2 of <em>The Java Language + * Specification, Third Edition</em> (JLS3). + * + * <p>If the receiver or the argument is a recovered type, the answer is always false, + * unless the two types are identical or the argument is <code>java.lang.Object</code>.</p> + * + * @param variableType the type of a variable to check compatibility against + * @return <code>true</code> if an expression of this type can be assigned to a + * variable of the given type, and <code>false</code> otherwise + * @since 3.1 + */ + public boolean isAssignmentCompatible(ITypeBinding variableType); + + /** + * Returns whether this type binding represents a capture binding. + * <p> + * Capture bindings result from capture conversion as specified + * in section 5.1.10 of <em>The Java Language Specification, + * Third Edition</em> (JLS3). + * </p> + * <p> + * A capture binding may have upper bounds and a lower bound. + * Upper bounds may be accessed using {@link #getTypeBounds()}, + * the lower bound must be accessed indirectly through the associated + * wildcard {@link #getWildcard()} when it is a lower bound wildcard. + * </p> + * <p> + * Note that capture bindings are distinct from type variables + * (even though they are often depicted as synthetic type + * variables); as such, {@link #isTypeVariable()} answers + * <code>false</code> for capture bindings, and + * {@link #isCapture()} answers <code>false</code> for type variables. + * </p> + * + * @return <code>true</code> if this type binding is a capture, + * and <code>false</code> otherwise + * @see #getTypeBounds() + * @see #getWildcard() + * @since 3.1 + */ + public boolean isCapture(); + + /** + * Returns whether this type is cast compatible with the given type, + * as specified in section 5.5 of <em>The Java Language + * Specification, Third Edition</em> (JLS3). + * <p> + * NOTE: The cast compatibility check performs backwards. + * When testing whether type B can be cast to type A, one would use: + * <code>A.isCastCompatible(B)</code> + * </p> + * + * <p>If the receiver or the argument is a recovered type, the answer is always false, + * unless the two types are identical or the argument is <code>java.lang.Object</code>.</p> + * + * @param type the type to check compatibility against + * @return <code>true</code> if this type is cast compatible with the + * given type, and <code>false</code> otherwise + * @since 3.1 + */ + public boolean isCastCompatible(ITypeBinding type); + + /** + * Returns whether this type binding represents a class type or a recovered binding. + * + * @return <code>true</code> if this object represents a class or a recovered binding, + * and <code>false</code> otherwise + */ + public boolean isClass(); + + /** + * Returns whether this type binding represents an enum type. + * + * @return <code>true</code> if this object represents an enum type, + * and <code>false</code> otherwise + * @since 3.1 + */ + public boolean isEnum(); + + /** + * Returns whether this type binding originated in source code. + * Returns <code>false</code> for all primitive types, the null type, + * array types, and for all classes, interfaces, enums, annotation + * types, type variables, parameterized type references, + * raw type references, wildcard types, and capture bindings + * whose information came from a pre-compiled binary class file. + * + * @return <code>true</code> if the type is in source code, + * and <code>false</code> otherwise + */ + public boolean isFromSource(); + + /** + * Returns whether this type binding represents a declaration of + * a generic class or interface. + * <p> + * Note that type parameters only occur on the binding of the + * declaring generic class or interface; e.g., <code>Collection<T></code>. + * Type bindings corresponding to a raw or parameterized reference to a generic + * type do not carry type parameters (they instead have non-empty type arguments + * and non-trivial erasure). + * This method is fully equivalent to <code>getTypeParameters().length > 0)</code>. + * </p> + * <p> + * Note that {@link #isGenericType()}, + * {@link #isParameterizedType()}, + * and {@link #isRawType()} are mutually exclusive. + * </p> + * + * @return <code>true</code> if this type binding represents a + * declaration of a generic class or interface, and <code>false</code> otherwise + * @see #getTypeParameters() + * @since 3.1 + */ + public boolean isGenericType(); + + /** + * Returns whether this type binding represents an interface type. + * <p> + * Note that an interface can also be an annotation type. + * </p> + * + * @return <code>true</code> if this object represents an interface, + * and <code>false</code> otherwise + */ + public boolean isInterface(); + +//{ObjectTeams: added isTeam(), isRole(), getBaseClass(), isClassPartOf(), getOptimalName() + /** + * Returns whether this type binding represents a team type. + * + * @return <code>true</code> if this object represents a team, + * and <code>false</code> otherwise + */ + public boolean isTeam(); + + /** + * Returns whether this type binding represents a role type. + * + * @return <code>true</code> if this object represents a role, + * and <code>false</code> otherwise + */ + public boolean isRole(); + + /** + * Returns whether this binding is the classpart of other binding + * (which must then be the interface part ;-) + * + * @param other + * @return + */ + public boolean isClassPartOf(ITypeBinding other); + + /** + * Returns whether this binding is the synthetic interface part of a role + */ + public boolean isSynthRoleIfc(); + + /** + * For a role class returns the corresponding interface part. + */ + public ITypeBinding getIfcPart(); + + /** + * Returns the type binding for the baseclass of the type represented + * by this class binding. + * @return the baseclass of the class represented by this type binding, + * or <code>null</code> if none + */ + public ITypeBinding getBaseClass(); + + /** + * Returns the name of this type as getQualifiedName() would do, + * but respect anchored types. + * + * @return + */ + public String getOptimalName(); +//km} + +//{ObjectTeams: tsuper types for roles via role model: + /** + * Returns the super roles of this type. + * @return super roles or null, if not a role. + */ + public ITypeBinding[] getSuperRoles(); +//mkr} + /** + * Returns whether this type binding represents a local class. + * <p> + * A local class is any nested class or enum type not declared as a member + * of another class or interface. A local class is a subspecies of nested + * type, and mutually exclusive with member types. Note that anonymous + * classes are a subspecies of local classes. + * </p> + * <p> + * Also note that interfaces and annotation types cannot be local. + * </p> + * + * @return <code>true</code> if this type binding is for a local class or + * enum type, and <code>false</code> otherwise + */ + public boolean isLocal(); + + /** + * Returns whether this type binding represents a member class or + * interface. + * <p> + * A member type is any type declared as a member of + * another type. A member type is a subspecies of nested + * type, and mutually exclusive with local types. + * </p> + * + * @return <code>true</code> if this type binding is for a member class, + * interface, enum, or annotation type, and <code>false</code> otherwise + */ + public boolean isMember(); + + /** + * Returns whether this type binding represents a nested class, interface, + * enum, or annotation type. + * <p> + * A nested type is any type whose declaration occurs within + * the body of another. The set of nested types is disjoint from the set of + * top-level types. Nested types further subdivide into member types, local + * types, and anonymous types. + * </p> + * + * @return <code>true</code> if this type binding is for a nested class, + * interface, enum, or annotation type, and <code>false</code> otherwise + */ + public boolean isNested(); + + /** + * Returns whether this type binding represents the null type. + * <p> + * The null type is the type of a <code>NullLiteral</code> node. + * </p> + * + * @return <code>true</code> if this type binding is for the null type, + * and <code>false</code> otherwise + */ + public boolean isNullType(); + + /** + * Returns whether this type binding represents an instance of + * a generic type corresponding to a parameterized type reference. + * <p> + * For example, an AST type like + * <code>Collection<String></code> typically resolves to a + * type binding whose type argument is the type binding for the + * class <code>java.lang.String</code> and whose erasure is the type + * binding for the generic type <code>java.util.Collection</code>. + * </p> + * <p> + * Note that {@link #isGenericType()}, + * {@link #isParameterizedType()}, + * and {@link #isRawType()} are mutually exclusive. + * </p> + * + * @return <code>true</code> if this type binding represents a + * an instance of a generic type corresponding to a parameterized + * type reference, and <code>false</code> otherwise + * @see #getTypeArguments() + * @see #getTypeDeclaration() + * @since 3.1 + */ + public boolean isParameterizedType(); + + /** + * Returns whether this type binding represents a primitive type. + * <p> + * There are nine predefined type bindings to represent the eight primitive + * types and <code>void</code>. These have the same names as the primitive + * types that they represent, namely boolean, byte, char, short, int, + * long, float, and double, and void. + * </p> + * + * @return <code>true</code> if this type binding is for a primitive type, + * and <code>false</code> otherwise + */ + public boolean isPrimitive(); + + /** + * Returns whether this type binding represents an instance of + * a generic type corresponding to a raw type reference. + * <p> + * For example, an AST type like + * <code>Collection</code> typically resolves to a + * type binding whose type argument is the type binding for + * the class <code>java.lang.Object</code> (the + * default bound for the single type parameter of + * <code>java.util.Collection</code>) and whose erasure is the + * type binding for the generic type + * <code>java.util.Collection</code>. + * </p> + * <p> + * Note that {@link #isGenericType()}, + * {@link #isParameterizedType()}, + * and {@link #isRawType()} are mutually exclusive. + * </p> + * + * @return <code>true</code> if this type binding represents a + * an instance of a generic type corresponding to a raw + * type reference, and <code>false</code> otherwise + * @see #getTypeDeclaration() + * @see #getTypeArguments() + * @since 3.1 + */ + public boolean isRawType(); + + /** + * Returns whether this type is subtype compatible with the given type, + * as specified in section 4.10 of <em>The Java Language + * Specification, Third Edition</em> (JLS3). + * + * <p>If the receiver or the argument is a recovered type, the answer is always false, + * unless the two types are identical or the argument is <code>java.lang.Object</code>.</p> + * + * @param type the type to check compatibility against + * @return <code>true</code> if this type is subtype compatible with the + * given type, and <code>false</code> otherwise + * @since 3.1 + */ + public boolean isSubTypeCompatible(ITypeBinding type); + + /** + * Returns whether this type binding represents a top-level class, + * interface, enum, or annotation type. + * <p> + * A top-level type is any type whose declaration does not occur within the + * body of another type declaration. The set of top level types is disjoint + * from the set of nested types. + * </p> + * + * @return <code>true</code> if this type binding is for a top-level class, + * interface, enum, or annotation type, and <code>false</code> otherwise + */ + public boolean isTopLevel(); + + /** + * Returns whether this type binding represents a type variable. + * Type variables bindings carry the type variable's bounds. + * <p> + * Note that type variables are distinct from capture bindings + * (even though capture bindings are often depicted as synthetic + * type variables); as such, {@link #isTypeVariable()} answers + * <code>false</code> for capture bindings, and + * {@link #isCapture()} answers <code>false</code> for type variables. + * </p> + * + * @return <code>true</code> if this type binding is for a type variable, + * and <code>false</code> otherwise + * @see #getName() + * @see #getTypeBounds() + * @since 3.1 + */ + public boolean isTypeVariable(); + + /** + * Returns whether this wildcard type is an upper bound + * ("extends") as opposed to a lower bound ("super"). + * Note that this property is only relevant for wildcards + * that have a bound. + * + * @return <code>true</code> if this wildcard type has a bound that is + * an upper bound, and <code>false</code> in all other cases + * @see #isWildcardType() + * @see #getBound() + * @since 3.1 + */ + public boolean isUpperbound(); + + /** + * Returns whether this type binding represents a wildcard type. A wildcard + * type occus only as an argument to a parameterized type reference. + * <p> + * For example, a AST type like + * <code>Collection<? extends Object></code> typically resolves to a + * parameterized type binding whose type argument is a wildcard type + * with upper type bound <code>java.util.Object</code>. + * </p> + * + * @return <code>true</code> if this object represents a wildcard type, + * and <code>false</code> otherwise + * @since 3.1 + * @see #getBound() + * @see #isUpperbound() + */ + public boolean isWildcardType(); + +//{ObjectTeams: new queries + /** + * Returns whether this type binding represents a dependent type. + * @param onlyRelevant only report dependence on relevant (non-tthis) anchors + */ + boolean isDependentType(boolean onlyRelevant); + + /** + * If this type binding represents a dependent type + * return the path of its type anchor. + * @return path or empty array. + */ + public String[] getAnchorPath(); +// SH} +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IVariableBinding.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IVariableBinding.java new file mode 100644 index 000000000..c86e397c4 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IVariableBinding.java @@ -0,0 +1,161 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +/** + * A variable binding represents either a field of a class or interface, or + * a local variable declaration (including formal parameters, local variables, + * and exception variables). + * + * @see ITypeBinding#getDeclaredFields() + * @since 2.0 + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface IVariableBinding extends IBinding { + + /** + * Returns whether this binding is for a field. + * Note that this method returns <code>true</code> for constants, + * including enum constants. This method returns <code>false</code> + * for local variables. + * + * @return <code>true</code> if this is the binding for a field, + * and <code>false</code> otherwise + */ + public boolean isField(); + + /** + * Returns whether this binding is for an enum constant. + * Note that this method returns <code>false</code> for local variables + * and for fields other than enum constants. + * + * @return <code>true</code> if this is the binding for an enum constant, + * and <code>false</code> otherwise + * @since 3.1 + */ + public boolean isEnumConstant(); + + /** + * Returns whether this binding corresponds to a parameter. + * + * @return <code>true</code> if this is the binding for a parameter, + * and <code>false</code> otherwise + * @since 3.2 + */ + public boolean isParameter(); + + /** + * Returns the name of the field or local variable declared in this binding. + * The name is always a simple identifier. + * + * @return the name of this field or local variable + */ + public String getName(); + + /** + * Returns the type binding representing the class or interface + * that declares this field. + * <p> + * The declaring class of a field is the class or interface of which it is + * a member. Local variables have no declaring class. The field length of an + * array type has no declaring class. + * </p> + * + * @return the binding of the class or interface that declares this field, + * or <code>null</code> if none + */ + public ITypeBinding getDeclaringClass(); + + /** + * Returns the binding for the type of this field or local variable. + * + * @return the binding for the type of this field or local variable + */ + public ITypeBinding getType(); + + /** + * Returns a small integer variable id for this variable binding. + * <p> + * <b>Local variables inside methods:</b> Local variables (and parameters) + * declared within a single method are assigned ascending ids in normal + * code reading order; var1.getVariableId()<var2.getVariableId() means that var1 is + * declared before var2. + * </p> + * <p> + * <b>Local variables outside methods:</b> Local variables declared in a + * type's static initializers (or initializer expressions of static fields) + * are assigned ascending ids in normal code reading order. Local variables + * declared in a type's instance initializers (or initializer expressions + * of non-static fields) are assigned ascending ids in normal code reading + * order. These ids are useful when checking definite assignment for + * static initializers (JLS 16.7) and instance initializers (JLS 16.8), + * respectively. + * </p> + * <p> + * <b>Fields:</b> Fields declared as members of a type are assigned + * ascending ids in normal code reading order; + * field1.getVariableId()<field2.getVariableId() means that field1 is declared before + * field2. + * </p> + * + * @return a small non-negative variable id + */ + public int getVariableId(); + + /** + * Returns this binding's constant value if it has one. + * Some variables may have a value computed at compile-time. If the type of + * the value is a primitive type, the result is the boxed equivalent (i.e., + * int returned as an <code>Integer</code>). If the type of the value is + * <code>String</code>, the result is the string itself. If the variable has + * no compile-time computed value, the result is <code>null</code>. + * (Note: compile-time constant expressions cannot denote <code>null</code>; + * JLS2 15.28.). The result is always <code>null</code> for enum constants. + * + * @return the constant value, or <code>null</code> if none + * @since 3.0 + */ + public Object getConstantValue(); + + /** + * Returns the method binding representing the method containing the scope + * in which this local variable is declared. + * <p> + * The declaring method of a method formal parameter is the method itself. + * For a local variable declared somewhere within the body of a method, + * the declaring method is the enclosing method. When local or anonymous + * classes are involved, the declaring method is the innermost such method. + * There is no declaring method for a field, or for a local variable + * declared in a static or instance initializer; this method returns + * <code>null</code> in those cases. + * </p> + * + * @return the binding of the method or constructor that declares this + * local variable, or <code>null</code> if none + * @since 3.1 + */ + public IMethodBinding getDeclaringMethod(); + + /** + * Returns the binding for the variable declaration corresponding to this + * variable binding. For a binding for a field declaration in an instance + * of a generic type, this method returns the binding for the corresponding + * field declaration in the generic type. For other variable bindings, + * including all ones for local variables and parameters, this method + * returns the same binding. + * + * @return the variable binding for the originating declaration + * @since 3.1 + */ + public IVariableBinding getVariableDeclaration(); + +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IfStatement.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IfStatement.java new file mode 100644 index 000000000..e35db215e --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IfStatement.java @@ -0,0 +1,348 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * If statement AST node type. + * <pre> + * IfStatement: + * <b>if</b> <b>(</b> Expression <b>)</b> Statement [ <b>else</b> Statement] + * </pre> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class IfStatement extends Statement { + + /** + * The "expression" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor EXPRESSION_PROPERTY = + new ChildPropertyDescriptor(IfStatement.class, "expression", Expression.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "thenStatement" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor THEN_STATEMENT_PROPERTY = + new ChildPropertyDescriptor(IfStatement.class, "thenStatement", Statement.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "elseStatement" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor ELSE_STATEMENT_PROPERTY = + new ChildPropertyDescriptor(IfStatement.class, "elseStatement", Statement.class, OPTIONAL, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List properyList = new ArrayList(4); + createPropertyList(IfStatement.class, properyList); + addProperty(EXPRESSION_PROPERTY, properyList); + addProperty(THEN_STATEMENT_PROPERTY, properyList); + addProperty(ELSE_STATEMENT_PROPERTY, properyList); + PROPERTY_DESCRIPTORS = reapPropertyList(properyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The expression; lazily initialized; defaults to an unspecified, but + * legal, expression. + */ + private Expression expression = null; + + /** + * The then statement; lazily initialized; defaults to an unspecified, but + * legal, statement. + */ + private Statement thenStatement = null; + + /** + * The else statement; <code>null</code> for none; defaults to none. + */ + private Statement optionalElseStatement = null; + + /** + * Creates a new unparented if statement node owned by the given + * AST. By default, the expresssion is unspecified, + * but legal, the then statement is an empty block, and there is no else + * statement. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + IfStatement(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == EXPRESSION_PROPERTY) { + if (get) { + return getExpression(); + } else { + setExpression((Expression) child); + return null; + } + } + if (property == THEN_STATEMENT_PROPERTY) { + if (get) { + return getThenStatement(); + } else { + setThenStatement((Statement) child); + return null; + } + } + if (property == ELSE_STATEMENT_PROPERTY) { + if (get) { + return getElseStatement(); + } else { + setElseStatement((Statement) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return IF_STATEMENT; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + IfStatement result = new IfStatement(target); + result.setSourceRange(getStartPosition(), getLength()); + result.copyLeadingComment(this); + result.setExpression((Expression) getExpression().clone(target)); + result.setThenStatement( + (Statement) getThenStatement().clone(target)); + result.setElseStatement( + (Statement) ASTNode.copySubtree(target, getElseStatement())); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + acceptChild(visitor, getExpression()); + acceptChild(visitor, getThenStatement()); + acceptChild(visitor, getElseStatement()); + } + visitor.endVisit(this); + } + + /** + * Returns the expression of this if statement. + * + * @return the expression node + */ + public Expression getExpression() { + if (this.expression == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.expression == null) { + preLazyInit(); + this.expression = new SimpleName(this.ast); + postLazyInit(this.expression, EXPRESSION_PROPERTY); + } + } + } + return this.expression; + } + + /** + * Sets the condition of this if statement. + * + * @param expression the expression node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setExpression(Expression expression) { + if (expression == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.expression; + preReplaceChild(oldChild, expression, EXPRESSION_PROPERTY); + this.expression = expression; + postReplaceChild(oldChild, expression, EXPRESSION_PROPERTY); + } + + /** + * Returns the "then" part of this if statement. + * + * @return the "then" statement node + */ + public Statement getThenStatement() { + if (this.thenStatement == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.thenStatement == null) { + preLazyInit(); + this.thenStatement = new Block(this.ast); + postLazyInit(this.thenStatement, THEN_STATEMENT_PROPERTY); + } + } + } + return this.thenStatement; + } + + /** + * Sets the "then" part of this if statement. + * <p> + * Special note: The Java language does not allow a local variable declaration + * to appear as the "then" part of an if statement (they may only appear within a + * block). However, the AST will allow a <code>VariableDeclarationStatement</code> + * as the thenStatement of a <code>IfStatement</code>. To get something that will + * compile, be sure to embed the <code>VariableDeclarationStatement</code> + * inside a <code>Block</code>. + * </p> + * + * @param statement the "then" statement node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setThenStatement(Statement statement) { + if (statement == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.thenStatement; + preReplaceChild(oldChild, statement, THEN_STATEMENT_PROPERTY); + this.thenStatement = statement; + postReplaceChild(oldChild, statement, THEN_STATEMENT_PROPERTY); + } + + /** + * Returns the "else" part of this if statement, or <code>null</code> if + * this if statement has <b>no</b> "else" part. + * <p> + * Note that there is a subtle difference between having no else + * statement and having an empty statement ("{}") or null statement (";"). + * </p> + * + * @return the "else" statement node, or <code>null</code> if none + */ + public Statement getElseStatement() { + return this.optionalElseStatement; + } + + /** + * Sets or clears the "else" part of this if statement. + * <p> + * Note that there is a subtle difference between having no else part + * (as in <code>"if(true){}"</code>) and having an empty block (as in + * "if(true){}else{}") or null statement (as in "if(true){}else;"). + * </p> + * <p> + * Special note: The Java language does not allow a local variable declaration + * to appear as the "else" part of an if statement (they may only appear within a + * block). However, the AST will allow a <code>VariableDeclarationStatement</code> + * as the elseStatement of a <code>IfStatement</code>. To get something that will + * compile, be sure to embed the <code>VariableDeclarationStatement</code> + * inside a <code>Block</code>. + * </p> + * + * @param statement the "else" statement node, or <code>null</code> if + * there is none + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setElseStatement(Statement statement) { + ASTNode oldChild = this.optionalElseStatement; + preReplaceChild(oldChild, statement, ELSE_STATEMENT_PROPERTY); + this.optionalElseStatement = statement; + postReplaceChild(oldChild, statement, ELSE_STATEMENT_PROPERTY); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return super.memSize() + 3 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.expression == null ? 0 : getExpression().treeSize()) + + (this.thenStatement == null ? 0 : getThenStatement().treeSize()) + + (this.optionalElseStatement == null ? 0 : getElseStatement().treeSize()); + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ImportDeclaration.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ImportDeclaration.java new file mode 100644 index 000000000..7ad6c7da7 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ImportDeclaration.java @@ -0,0 +1,446 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + * Technical University Berlin - extended API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Import declaration AST node type. + * + * For JLS2: + * <pre> + * ImportDeclaration: + * <b>import</b> Name [ <b>.</b> <b>*</b> ] <b>;</b> + * </pre> + * For JLS3, static was added: + * <pre> + * ImportDeclaration: + * <b>import</b> [ <b>static</b> ] Name [ <b>.</b> <b>*</b> ] <b>;</b> + * </pre> + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class ImportDeclaration extends ASTNode { + + /** + * The "name" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor NAME_PROPERTY = + new ChildPropertyDescriptor(ImportDeclaration.class, "name", Name.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "onDemand" structural property of this node type. + * @since 3.0 + */ + public static final SimplePropertyDescriptor ON_DEMAND_PROPERTY = + new SimplePropertyDescriptor(ImportDeclaration.class, "onDemand", boolean.class, MANDATORY); //$NON-NLS-1$ + + /** + * The "static" structural property of this node type (added in JLS3 API). + * @since 3.1 + */ + public static final SimplePropertyDescriptor STATIC_PROPERTY = + new SimplePropertyDescriptor(ImportDeclaration.class, "static", boolean.class, MANDATORY); //$NON-NLS-1$ + +//{ObjectTeams: new flag + /** + * The "base" structural property of this node type (added in JLS3 API). + * @since 3.2 + */ + public static final SimplePropertyDescriptor BASE_PROPERTY = + new SimplePropertyDescriptor(ImportDeclaration.class, "base", boolean.class, MANDATORY); //$NON-NLS-1$ +// SH} + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + * @since 3.0 + */ + private static final List PROPERTY_DESCRIPTORS_2_0; + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + * @since 3.1 + */ + private static final List PROPERTY_DESCRIPTORS_3_0; + + static { + List properyList = new ArrayList(3); + createPropertyList(ImportDeclaration.class, properyList); + addProperty(NAME_PROPERTY, properyList); + addProperty(ON_DEMAND_PROPERTY, properyList); + PROPERTY_DESCRIPTORS_2_0 = reapPropertyList(properyList); + + properyList = new ArrayList(4); + createPropertyList(ImportDeclaration.class, properyList); + addProperty(STATIC_PROPERTY, properyList); +//{ObjectTeams: base imports: + addProperty(BASE_PROPERTY, properyList); +// SH} + addProperty(NAME_PROPERTY, properyList); + addProperty(ON_DEMAND_PROPERTY, properyList); + PROPERTY_DESCRIPTORS_3_0 = reapPropertyList(properyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + if (apiLevel == AST.JLS2_INTERNAL) { + return PROPERTY_DESCRIPTORS_2_0; + } else { + return PROPERTY_DESCRIPTORS_3_0; + } + } + + /** + * The import name; lazily initialized; defaults to a unspecified, + * legal Java identifier. + */ + private Name importName = null; + + /** + * On demand versus single type import; defaults to single type import. + */ + private boolean onDemand = false; + + /** + * Static versus regular; defaults to regular import. + * Added in JLS3; not used in JLS2. + * @since 3.1 + */ + private boolean isStatic = false; + +//{ObjectTeams: + /** + * Base versus regular; defaults to regular import. + * Added in JLS3; not used in JLS2. + * @since 3.2 + */ + private boolean isBase = false; +// SH} + /** + * Creates a new AST node for an import declaration owned by the + * given AST. The import declaration initially is a regular (non-static) + * single type import for an unspecified, but legal, Java type name. + * <p> + * N.B. This constructor is package-private; all subclasses must be + * declared in the same package; clients are unable to declare + * additional subclasses. + * </p> + * + * @param ast the AST that is to own this node + */ + ImportDeclaration(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean internalGetSetBooleanProperty(SimplePropertyDescriptor property, boolean get, boolean value) { + if (property == ON_DEMAND_PROPERTY) { + if (get) { + return isOnDemand(); + } else { + setOnDemand(value); + return false; + } + } + if (property == STATIC_PROPERTY) { + if (get) { + return isStatic(); + } else { + setStatic(value); + return false; + } + } +//{ObjectTeams: + if (property == BASE_PROPERTY) { + if (get) { + return isBase(); + } else { + setBase(value); + return false; + } + } +// SH} + // allow default implementation to flag the error + return super.internalGetSetBooleanProperty(property, get, value); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == NAME_PROPERTY) { + if (get) { + return getName(); + } else { + setName((Name) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return IMPORT_DECLARATION; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + ImportDeclaration result = new ImportDeclaration(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setOnDemand(isOnDemand()); + if (this.ast.apiLevel >= AST.JLS3) { + result.setStatic(isStatic()); + } +//{ObjectTeams: + if (this.ast.apiLevel >= AST.JLS3) { + result.setBase(isBase()); + } +// SH} + result.setName((Name) getName().clone(target)); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + acceptChild(visitor, getName()); + } + visitor.endVisit(this); + } + + /** + * Returns the name imported by this declaration. + * <p> + * For a regular on-demand import, this is the name of a package. + * For a static on-demand import, this is the qualified name of + * a type. For a regular single-type import, this is the qualified name + * of a type. For a static single-type import, this is the qualified name + * of a static member of a type. + * </p> + * + * @return the imported name node + */ + public Name getName() { + if (this.importName == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.importName == null) { + preLazyInit(); + this.importName =this.ast.newQualifiedName( + new SimpleName(this.ast), new SimpleName(this.ast)); + postLazyInit(this.importName, NAME_PROPERTY); + } + } + } + return this.importName; + } + + /** + * Sets the name of this import declaration to the given name. + * <p> + * For a regular on-demand import, this is the name of a package. + * For a static on-demand import, this is the qualified name of + * a type. For a regular single-type import, this is the qualified name + * of a type. For a static single-type import, this is the qualified name + * of a static member of a type. + * </p> + * + * @param name the new import name + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public void setName(Name name) { + if (name == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.importName; + preReplaceChild(oldChild, name, NAME_PROPERTY); + this.importName = name; + postReplaceChild(oldChild, name, NAME_PROPERTY); + } + + /** + * Returns whether this import declaration is an on-demand or a + * single-type import. + * + * @return <code>true</code> if this is an on-demand import, + * and <code>false</code> if this is a single type import + */ + public boolean isOnDemand() { + return this.onDemand; + } + + /** + * Sets whether this import declaration is an on-demand or a + * single-type import. + * + * @param onDemand <code>true</code> if this is an on-demand import, + * and <code>false</code> if this is a single type import + */ + public void setOnDemand(boolean onDemand) { + preValueChange(ON_DEMAND_PROPERTY); + this.onDemand = onDemand; + postValueChange(ON_DEMAND_PROPERTY); + } + + /** + * Returns whether this import declaration is a static import (added in JLS3 API). + * + * @return <code>true</code> if this is a static import, + * and <code>false</code> if this is a regular import + * @exception UnsupportedOperationException if this operation is used in + * a JLS2 AST + * @since 3.1 + */ + public boolean isStatic() { + unsupportedIn2(); + return this.isStatic; + } + + /** + * Sets whether this import declaration is a static import (added in JLS3 API). + * + * @param isStatic <code>true</code> if this is a static import, + * and <code>false</code> if this is a regular import + * @exception UnsupportedOperationException if this operation is used in + * a JLS2 AST + * @since 3.1 + */ + public void setStatic(boolean isStatic) { + unsupportedIn2(); + preValueChange(STATIC_PROPERTY); + this.isStatic = isStatic; + postValueChange(STATIC_PROPERTY); + } + +//{ObjectTeams: new flag: + /** + * Returns whether this import declaration is a base import (added in JLS3 API). + * + * @return <code>true</code> if this is a base import, + * and <code>false</code> if this is a regular import + * @exception UnsupportedOperationException if this operation is used in + * a JLS2 AST + * @since 3.2 + */ + public boolean isBase() { + unsupportedIn2(); + return isBase; + } + + /** + * Sets whether this import declaration is a base import (added in JLS3 API). + * + * @param isBase <code>true</code> if this is a base import, + * and <code>false</code> if this is a regular import + * @exception UnsupportedOperationException if this operation is used in + * a JLS2 AST + * @since 3.1 + */ + public void setBase(boolean isBase) { + unsupportedIn2(); + preValueChange(BASE_PROPERTY); + this.isBase = isBase; + postValueChange(BASE_PROPERTY); + } +// SH} + + /** + * Resolves and returns the binding for the package, type, field, or + * method named in this import declaration. + * <p> + * The name specified in a non-static single-type import can resolve + * to a type (only). The name specified in a non-static on-demand + * import can itself resolve to either a package or a type. + * For static imports (introduced in JLS3), the name specified in a + * static on-demand import can itself resolve to a type (only). + * The name specified in a static single import can resolve to a + * type, field, or method; in cases where the name could be resolved + * to more than one element with that name (for example, two + * methods both named "max", or a method and a field), this method + * returns one of the plausible bindings. + * </p> + * <p> + * Note that bindings are generally unavailable unless requested when the + * AST is being built. + * </p> + * + * @return a package, type, field, or method binding, or <code>null</code> + * if the binding cannot be resolved + */ + public IBinding resolveBinding() { + return this.ast.getBindingResolver().resolveImport(this); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return BASE_NODE_SIZE + 3 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.importName == null ? 0 : getName().treeSize()); + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/InfixExpression.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/InfixExpression.java new file mode 100644 index 000000000..314aef52f --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/InfixExpression.java @@ -0,0 +1,538 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Infix expression AST node type. + * <pre> + * InfixExpression: + * Expression InfixOperator Expression { InfixOperator Expression } + * </pre> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class InfixExpression extends Expression { + + /** + * Infix operators (typesafe enumeration). + * <pre> + * InfixOperator:<code> + * <b>*</b> TIMES + * <b>/</b> DIVIDE + * <b>%</b> REMAINDER + * <b>+</b> PLUS + * <b>-</b> MINUS + * <b><<</b> LEFT_SHIFT + * <b>>></b> RIGHT_SHIFT_SIGNED + * <b>>>></b> RIGHT_SHIFT_UNSIGNED + * <b><</b> LESS + * <b>></b> GREATER + * <b><=</b> LESS_EQUALS + * <b>>=</b> GREATER_EQUALS + * <b>==</b> EQUALS + * <b>!=</b> NOT_EQUALS + * <b>^</b> XOR + * <b>&</b> AND + * <b>|</b> OR + * <b>&&</b> CONDITIONAL_AND + * <b>||</b> CONDITIONAL_OR</code> + * </pre> + */ + public static class Operator { + + /** + * The token for the operator. + */ + private String token; + + /** + * Creates a new infix operator with the given token. + * <p> + * Note: this constructor is private. The only instances + * ever created are the ones for the standard operators. + * </p> + * + * @param token the character sequence for the operator + */ + private Operator(String token) { + this.token = token; + } + + /** + * Returns the character sequence for the operator. + * + * @return the character sequence for the operator + */ + public String toString() { + return this.token; + } + + /** Multiplication "*" operator. */ + public static final Operator TIMES = new Operator("*");//$NON-NLS-1$ + /** Division "/" operator. */ + public static final Operator DIVIDE = new Operator("/");//$NON-NLS-1$ + /** Remainder "%" operator. */ + public static final Operator REMAINDER = new Operator("%");//$NON-NLS-1$ + /** Addition (or string concatenation) "+" operator. */ + public static final Operator PLUS = new Operator("+");//$NON-NLS-1$ + /** Subtraction "-" operator. */ + public static final Operator MINUS = new Operator("-");//$NON-NLS-1$ + /** Left shift "<<" operator. */ + public static final Operator LEFT_SHIFT = new Operator("<<");//$NON-NLS-1$ + /** Signed right shift ">>" operator. */ + public static final Operator RIGHT_SHIFT_SIGNED = new Operator(">>");//$NON-NLS-1$ + /** Unsigned right shift ">>>" operator. */ + public static final Operator RIGHT_SHIFT_UNSIGNED = + new Operator(">>>");//$NON-NLS-1$ + /** Less than "<" operator. */ + public static final Operator LESS = new Operator("<");//$NON-NLS-1$ + /** Greater than ">" operator. */ + public static final Operator GREATER = new Operator(">");//$NON-NLS-1$ + /** Less than or equals "<=" operator. */ + public static final Operator LESS_EQUALS = new Operator("<=");//$NON-NLS-1$ + /** Greater than or equals ">=;" operator. */ + public static final Operator GREATER_EQUALS = new Operator(">=");//$NON-NLS-1$ + /** Equals "==" operator. */ + public static final Operator EQUALS = new Operator("==");//$NON-NLS-1$ + /** Not equals "!=" operator. */ + public static final Operator NOT_EQUALS = new Operator("!=");//$NON-NLS-1$ + /** Exclusive OR "^" operator. */ + public static final Operator XOR = new Operator("^");//$NON-NLS-1$ + /** Inclusive OR "|" operator. */ + public static final Operator OR = new Operator("|");//$NON-NLS-1$ + /** AND "&" operator. */ + public static final Operator AND = new Operator("&");//$NON-NLS-1$ + /** Conditional OR "||" operator. */ + public static final Operator CONDITIONAL_OR = new Operator("||");//$NON-NLS-1$ + /** Conditional AND "&&" operator. */ + public static final Operator CONDITIONAL_AND = new Operator("&&");//$NON-NLS-1$ + + /** + * Map from token to operator (key type: <code>String</code>; + * value type: <code>Operator</code>). + */ + private static final Map CODES; + static { + CODES = new HashMap(20); + Operator[] ops = { + TIMES, + DIVIDE, + REMAINDER, + PLUS, + MINUS, + LEFT_SHIFT, + RIGHT_SHIFT_SIGNED, + RIGHT_SHIFT_UNSIGNED, + LESS, + GREATER, + LESS_EQUALS, + GREATER_EQUALS, + EQUALS, + NOT_EQUALS, + XOR, + OR, + AND, + CONDITIONAL_OR, + CONDITIONAL_AND, + }; + for (int i = 0; i < ops.length; i++) { + CODES.put(ops[i].toString(), ops[i]); + } + } + + /** + * Returns the infix operator corresponding to the given string, + * or <code>null</code> if none. + * <p> + * <code>toOperator</code> is the converse of <code>toString</code>: + * that is, <code>Operator.toOperator(op.toString()) == op</code> for + * all operators <code>op</code>. + * </p> + * + * @param token the character sequence for the operator + * @return the infix operator, or <code>null</code> if none + */ + public static Operator toOperator(String token) { + return (Operator) CODES.get(token); + } + + } + + /** + * The "leftOperand" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor LEFT_OPERAND_PROPERTY = + new ChildPropertyDescriptor(InfixExpression.class, "leftOperand", Expression.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "operator" structural property of this node type. + * @since 3.0 + */ + public static final SimplePropertyDescriptor OPERATOR_PROPERTY = + new SimplePropertyDescriptor(InfixExpression.class, "operator", InfixExpression.Operator.class, MANDATORY); //$NON-NLS-1$ + + /** + * The "rightOperand" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor RIGHT_OPERAND_PROPERTY = + new ChildPropertyDescriptor(InfixExpression.class, "rightOperand", Expression.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "extendedOperands" structural property of this node type. + * @since 3.0 + */ + public static final ChildListPropertyDescriptor EXTENDED_OPERANDS_PROPERTY = + new ChildListPropertyDescriptor(InfixExpression.class, "extendedOperands", Expression.class, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List properyList = new ArrayList(5); + createPropertyList(InfixExpression.class, properyList); + addProperty(LEFT_OPERAND_PROPERTY, properyList); + addProperty(OPERATOR_PROPERTY, properyList); + addProperty(RIGHT_OPERAND_PROPERTY, properyList); + addProperty(EXTENDED_OPERANDS_PROPERTY, properyList); + PROPERTY_DESCRIPTORS = reapPropertyList(properyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The infix operator; defaults to InfixExpression.Operator.PLUS. + */ + private InfixExpression.Operator operator = InfixExpression.Operator.PLUS; + + /** + * The left operand; lazily initialized; defaults to an unspecified, + * but legal, simple name. + */ + private Expression leftOperand = null; + + /** + * The right operand; lazily initialized; defaults to an unspecified, + * but legal, simple name. + */ + private Expression rightOperand = null; + + /** + * The list of extended operand expressions (element type: + * <code>Expression</code>). Lazily initialized; defaults to an empty list. + */ + private ASTNode.NodeList extendedOperands = null; + + /** + * Creates a new AST node for an infix expression owned by the given + * AST. By default, the node has unspecified (but legal) operator, + * left and right operands, and an empty list of additional operands. + * + * @param ast the AST that is to own this node + */ + InfixExpression(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final Object internalGetSetObjectProperty(SimplePropertyDescriptor property, boolean get, Object value) { + if (property == OPERATOR_PROPERTY) { + if (get) { + return getOperator(); + } else { + setOperator((Operator) value); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetObjectProperty(property, get, value); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == LEFT_OPERAND_PROPERTY) { + if (get) { + return getLeftOperand(); + } else { + setLeftOperand((Expression) child); + return null; + } + } + if (property == RIGHT_OPERAND_PROPERTY) { + if (get) { + return getRightOperand(); + } else { + setRightOperand((Expression) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalGetChildListProperty(ChildListPropertyDescriptor property) { + if (property == EXTENDED_OPERANDS_PROPERTY) { + return extendedOperands(); + } + // allow default implementation to flag the error + return super.internalGetChildListProperty(property); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return INFIX_EXPRESSION; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + InfixExpression result = new InfixExpression(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setOperator(getOperator()); + result.setLeftOperand((Expression) getLeftOperand().clone(target)); + result.setRightOperand((Expression) getRightOperand().clone(target)); + if (this.extendedOperands != null) { + // be careful not to trigger lazy creation of list + result.extendedOperands().addAll( + ASTNode.copySubtrees(target, extendedOperands())); + } + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + acceptChild(visitor, getLeftOperand()); + acceptChild(visitor, getRightOperand()); + if (this.extendedOperands != null) { + // be careful not to trigger lazy creation of list + acceptChildren(visitor, this.extendedOperands); + } + } + visitor.endVisit(this); + } + + /** + * Returns the operator of this infix expression. + * + * @return the infix operator + */ + public InfixExpression.Operator getOperator() { + return this.operator; + } + + /** + * Sets the operator of this infix expression. + * + * @param operator the infix operator + * @exception IllegalArgumentException if the argument is incorrect + */ + public void setOperator(InfixExpression.Operator operator) { + if (operator == null) { + throw new IllegalArgumentException(); + } + preValueChange(OPERATOR_PROPERTY); + this.operator = operator; + postValueChange(OPERATOR_PROPERTY); + } + + /** + * Returns the left operand of this infix expression. + * + * @return the left operand node + */ + public Expression getLeftOperand() { + if (this.leftOperand == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.leftOperand == null) { + preLazyInit(); + this.leftOperand= new SimpleName(this.ast); + postLazyInit(this.leftOperand, LEFT_OPERAND_PROPERTY); + } + } + } + return this.leftOperand; + } + + /** + * Sets the left operand of this infix expression. + * + * @param expression the left operand node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setLeftOperand(Expression expression) { + if (expression == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.leftOperand; + preReplaceChild(oldChild, expression, LEFT_OPERAND_PROPERTY); + this.leftOperand = expression; + postReplaceChild(oldChild, expression, LEFT_OPERAND_PROPERTY); + } + + /** + * Returns the right operand of this infix expression. + * + * @return the right operand node + */ + public Expression getRightOperand() { + if (this.rightOperand == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.rightOperand == null) { + preLazyInit(); + this.rightOperand= new SimpleName(this.ast); + postLazyInit(this.rightOperand, RIGHT_OPERAND_PROPERTY); + } + } + } + return this.rightOperand; + } + + /** + * Sets the right operand of this infix expression. + * + * @param expression the right operand node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setRightOperand(Expression expression) { + if (expression == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.rightOperand; + preReplaceChild(oldChild, expression, RIGHT_OPERAND_PROPERTY); + this.rightOperand = expression; + postReplaceChild(oldChild, expression, RIGHT_OPERAND_PROPERTY); + } + + /** + * Returns where there are any extended operands. + * + * @return <code>true</code> if there are one or more extended operands, + * and <code>false</code> if there are no extended operands + */ + public boolean hasExtendedOperands() { + return + (this.extendedOperands != null) && this.extendedOperands.size() > 0; + } + + /** + * Returns the live list of extended operands. + * <p> + * The extended operands is the preferred way of representing deeply nested + * expressions of the form <code>L op R op R2 op R3...</code> where + * the same operator appears between all the operands (the most + * common case being lengthy string concatenation expressions). Using + * the extended operands keeps the trees from getting too deep; this + * decreases the risk is running out of thread stack space at runtime + * when traversing such trees. + * ((a + b) + c) + d would be translated to: + * leftOperand: a + * rightOperand: b + * extendedOperands: {c, d} + * operator: + + * </p> + * + * @return the live list of extended operands + * (element type: <code>Expression</code>) + */ + public List extendedOperands() { + if (this.extendedOperands == null) { + // lazily initialize + this.extendedOperands = new ASTNode.NodeList(EXTENDED_OPERANDS_PROPERTY); + } + return this.extendedOperands; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + // treat Operator as free + return BASE_NODE_SIZE + 4 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.leftOperand == null ? 0 : getLeftOperand().treeSize()) + + (this.rightOperand == null ? 0 : getRightOperand().treeSize()) + + (this.extendedOperands == null ? 0 : this.extendedOperands.listSize()); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Initializer.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Initializer.java new file mode 100644 index 000000000..b0d5382ed --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Initializer.java @@ -0,0 +1,313 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Static or instance initializer AST node type. + * <pre> + * Initializer: + * [ <b>static</b> ] Block + * </pre> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class Initializer extends BodyDeclaration { + + /** + * The "javadoc" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor JAVADOC_PROPERTY = + internalJavadocPropertyFactory(Initializer.class); + + /** + * The "modifiers" structural property of this node type (JLS2 API only). + * @since 3.0 + */ + public static final SimplePropertyDescriptor MODIFIERS_PROPERTY = + internalModifiersPropertyFactory(Initializer.class); + + /** + * The "modifiers" structural property of this node type (added in JLS3 API). + * @since 3.1 + */ + public static final ChildListPropertyDescriptor MODIFIERS2_PROPERTY = + internalModifiers2PropertyFactory(Initializer.class); + + /** + * The "body" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor BODY_PROPERTY = + new ChildPropertyDescriptor(Initializer.class, "body", Block.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + * @since 3.0 + */ + private static final List PROPERTY_DESCRIPTORS_2_0; + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + * @since 3.1 + */ + private static final List PROPERTY_DESCRIPTORS_3_0; + + static { + List properyList = new ArrayList(4); + createPropertyList(Initializer.class, properyList); + addProperty(JAVADOC_PROPERTY, properyList); + addProperty(MODIFIERS_PROPERTY, properyList); + addProperty(BODY_PROPERTY, properyList); + PROPERTY_DESCRIPTORS_2_0 = reapPropertyList(properyList); + + properyList = new ArrayList(4); + createPropertyList(Initializer.class, properyList); + addProperty(JAVADOC_PROPERTY, properyList); + addProperty(MODIFIERS2_PROPERTY, properyList); + addProperty(BODY_PROPERTY, properyList); + PROPERTY_DESCRIPTORS_3_0 = reapPropertyList(properyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + if (apiLevel == AST.JLS2_INTERNAL) { + return PROPERTY_DESCRIPTORS_2_0; + } else { + return PROPERTY_DESCRIPTORS_3_0; + } + } + + /** + * The initializer body; lazily initialized; defaults to an empty block. + */ + private Block body = null; + + /** + * Creates a new AST node for an initializer declaration owned by the given + * AST. By default, the initializer has no modifiers and an empty block. + * The javadoc comment is not used for initializers. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + Initializer(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + * @since 3.0 + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int internalGetSetIntProperty(SimplePropertyDescriptor property, boolean get, int value) { + if (property == MODIFIERS_PROPERTY) { + if (get) { + return getModifiers(); + } else { + internalSetModifiers(value); + return 0; + } + } + // allow default implementation to flag the error + return super.internalGetSetIntProperty(property, get, value); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == JAVADOC_PROPERTY) { + if (get) { + return getJavadoc(); + } else { + setJavadoc((Javadoc) child); + return null; + } + } + if (property == BODY_PROPERTY) { + if (get) { + return getBody(); + } else { + setBody((Block) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalGetChildListProperty(ChildListPropertyDescriptor property) { + if (property == MODIFIERS2_PROPERTY) { + return modifiers(); + } + // allow default implementation to flag the error + return super.internalGetChildListProperty(property); + } + + /* (omit javadoc for this method) + * Method declared on BodyDeclaration. + */ + final ChildPropertyDescriptor internalJavadocProperty() { + return JAVADOC_PROPERTY; + } + + /* (omit javadoc for this method) + * Method declared on BodyDeclaration. + */ + final ChildListPropertyDescriptor internalModifiers2Property() { + return MODIFIERS2_PROPERTY; + } + + /* (omit javadoc for this method) + * Method declared on BodyDeclaration. + */ + final SimplePropertyDescriptor internalModifiersProperty() { + return MODIFIERS_PROPERTY; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return INITIALIZER; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + Initializer result = new Initializer(target); + result.setSourceRange(getStartPosition(), getLength()); + if (this.ast.apiLevel == AST.JLS2_INTERNAL) { + result.internalSetModifiers(getModifiers()); + } + if (this.ast.apiLevel >= AST.JLS3) { + result.modifiers().addAll(ASTNode.copySubtrees(target, modifiers())); + } + result.setJavadoc( + (Javadoc) ASTNode.copySubtree(target, getJavadoc())); + result.setBody((Block) getBody().clone(target)); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + acceptChild(visitor, getJavadoc()); + if (this.ast.apiLevel >= AST.JLS3) { + acceptChildren(visitor, this.modifiers); + } + acceptChild(visitor, getBody()); + } + visitor.endVisit(this); + } + + /** + * Returns the body of this initializer declaration. + * + * @return the initializer body + */ + public Block getBody() { + if (this.body == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.body == null) { + preLazyInit(); + this.body= new Block(this.ast); + postLazyInit(this.body, BODY_PROPERTY); + } + } + } + return this.body; + } + + /** + * Sets the body of this initializer declaration. + * + * @param body the block node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setBody(Block body) { + if (body == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.body; + preReplaceChild(oldChild, body, BODY_PROPERTY); + this.body = body; + postReplaceChild(oldChild, body, BODY_PROPERTY); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return super.memSize() + 1 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.optionalDocComment == null ? 0 : getJavadoc().treeSize()) + + (this.modifiers == null ? 0 : this.modifiers.listSize()) + + (this.body == null ? 0 : getBody().treeSize()); + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/InstanceofExpression.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/InstanceofExpression.java new file mode 100644 index 000000000..9c8396060 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/InstanceofExpression.java @@ -0,0 +1,263 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Instanceof expression AST node type. + * <pre> + * InstanceofExpression: + * Expression <b>instanceof</b> Type + * </pre> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class InstanceofExpression extends Expression { + + /** + * The "leftOperand" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor LEFT_OPERAND_PROPERTY = + new ChildPropertyDescriptor(InstanceofExpression.class, "leftOperand", Expression.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "rightOperand" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor RIGHT_OPERAND_PROPERTY = + new ChildPropertyDescriptor(InstanceofExpression.class, "rightOperand", Type.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List properyList = new ArrayList(3); + createPropertyList(InstanceofExpression.class, properyList); + addProperty(LEFT_OPERAND_PROPERTY, properyList); + addProperty(RIGHT_OPERAND_PROPERTY, properyList); + PROPERTY_DESCRIPTORS = reapPropertyList(properyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The left operand; lazily initialized; defaults to an unspecified, + * but legal, simple name. + */ + private Expression leftOperand = null; + + /** + * The right operand; lazily initialized; defaults to an unspecified, + * but legal, simple type. + */ + private Type rightOperand = null; + + /** + * Creates a new AST node for an instanceof expression owned by the given + * AST. By default, the node has unspecified (but legal) operator, + * left and right operands. + * + * @param ast the AST that is to own this node + */ + InstanceofExpression(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == LEFT_OPERAND_PROPERTY) { + if (get) { + return getLeftOperand(); + } else { + setLeftOperand((Expression) child); + return null; + } + } + if (property == RIGHT_OPERAND_PROPERTY) { + if (get) { + return getRightOperand(); + } else { + setRightOperand((Type) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return INSTANCEOF_EXPRESSION; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + InstanceofExpression result = new InstanceofExpression(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setLeftOperand((Expression) getLeftOperand().clone(target)); + result.setRightOperand((Type) getRightOperand().clone(target)); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + acceptChild(visitor, getLeftOperand()); + acceptChild(visitor, getRightOperand()); + } + visitor.endVisit(this); + } + + /** + * Returns the left operand of this instanceof expression. + * + * @return the left operand node + */ + public Expression getLeftOperand() { + if (this.leftOperand == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.leftOperand == null) { + preLazyInit(); + this.leftOperand= new SimpleName(this.ast); + postLazyInit(this.leftOperand, LEFT_OPERAND_PROPERTY); + } + } + } + return this.leftOperand; + } + + /** + * Sets the left operand of this instanceof expression. + * + * @param expression the left operand node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setLeftOperand(Expression expression) { + if (expression == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.leftOperand; + preReplaceChild(oldChild, expression, LEFT_OPERAND_PROPERTY); + this.leftOperand = expression; + postReplaceChild(oldChild, expression, LEFT_OPERAND_PROPERTY); + } + + /** + * Returns the right operand of this instanceof expression. + * + * @return the right operand node + */ + public Type getRightOperand() { + if (this.rightOperand == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.rightOperand == null) { + preLazyInit(); + this.rightOperand= new SimpleType(this.ast); + postLazyInit(this.rightOperand, RIGHT_OPERAND_PROPERTY); + } + } + } + return this.rightOperand; + } + + /** + * Sets the right operand of this instanceof expression. + * + * @param referenceType the right operand node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setRightOperand(Type referenceType) { + if (referenceType == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.rightOperand; + preReplaceChild(oldChild, referenceType, RIGHT_OPERAND_PROPERTY); + this.rightOperand = referenceType; + postReplaceChild(oldChild, referenceType, RIGHT_OPERAND_PROPERTY); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + // treat Operator as free + return BASE_NODE_SIZE + 2 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.leftOperand == null ? 0 : getLeftOperand().treeSize()) + + (this.rightOperand == null ? 0 : getRightOperand().treeSize()); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/InternalASTRewrite.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/InternalASTRewrite.java new file mode 100644 index 000000000..09cf2ff78 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/InternalASTRewrite.java @@ -0,0 +1,246 @@ +/******************************************************************************* + * Copyright (c) 2004, 2009 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.dom; +import java.util.Hashtable; +import java.util.List; +import java.util.Map; + +import org.eclipse.text.edits.MultiTextEdit; +import org.eclipse.text.edits.TextEdit; + +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.TextUtilities; + +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.dom.SimplePropertyDescriptor; +import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor; +import org.eclipse.jdt.core.dom.rewrite.TargetSourceRangeComputer; +import org.eclipse.jdt.internal.compiler.parser.RecoveryScannerData; +import org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer; +import org.eclipse.jdt.internal.core.dom.rewrite.LineInformation; +import org.eclipse.jdt.internal.core.dom.rewrite.ListRewriteEvent; +import org.eclipse.jdt.internal.core.dom.rewrite.NodeInfoStore; +import org.eclipse.jdt.internal.core.dom.rewrite.NodeRewriteEvent; +import org.eclipse.jdt.internal.core.dom.rewrite.RewriteEventStore; +import org.eclipse.jdt.internal.core.dom.rewrite.RewriteEventStore.CopySourceInfo; +import org.eclipse.jdt.internal.core.dom.rewrite.RewriteEventStore.PropertyLocation; + +/** + * Internal class: not intended to be used by client. + * When AST modifications recording is enabled, all changes are recorded by this class. + */ +class InternalASTRewrite extends NodeEventHandler { + + /** root node for the rewrite: Only nodes under this root are accepted */ + private CompilationUnit root; + + protected final RewriteEventStore eventStore; + protected final NodeInfoStore nodeStore; + protected final Hashtable clonedNodes; + + int cloneDepth = 0; + + /** + * Constructor + * @param root root node of the recorded ast. + */ + public InternalASTRewrite(CompilationUnit root) { + this.root = root; + this.eventStore = new RewriteEventStore(); + this.nodeStore = new NodeInfoStore(root.getAST()); + this.clonedNodes = new Hashtable(); + } + + /** + * Performs the rewrite: The rewrite events are translated to the corresponding in text changes. + * The given options can be null in which case the global options {@link JavaCore#getOptions() JavaCore.getOptions()} + * will be used. + * + * @param document Document which describes the code of the AST that is passed in in the + * constructor. This document is accessed read-only. + * @param options the given options + * @throws IllegalArgumentException if the rewrite fails + * @return Returns the edit describing the text changes. + */ + public TextEdit rewriteAST(IDocument document, Map options) { + TextEdit result = new MultiTextEdit(); + + final CompilationUnit rootNode = getRootNode(); + if (rootNode != null) { + TargetSourceRangeComputer xsrComputer = new TargetSourceRangeComputer() { + /** + * This implementation of + * {@link TargetSourceRangeComputer#computeSourceRange(ASTNode)} + * is specialized to work in the case of internal AST rewriting, where the + * original AST has been modified from its original form. This means that + * one cannot trust that the root of the given node is the compilation unit. + */ + public SourceRange computeSourceRange(ASTNode node) { + int extendedStartPosition = rootNode.getExtendedStartPosition(node); + int extendedLength = rootNode.getExtendedLength(node); + return new SourceRange(extendedStartPosition, extendedLength); + } + }; + char[] content= document.get().toCharArray(); + LineInformation lineInfo= LineInformation.create(document); + String lineDelim= TextUtilities.getDefaultLineDelimiter(document); + List comments= rootNode.getCommentList(); + + Map currentOptions = options == null ? JavaCore.getOptions() : options; + ASTRewriteAnalyzer visitor = new ASTRewriteAnalyzer(content, lineInfo, lineDelim, result, this.eventStore, this.nodeStore, comments, currentOptions, xsrComputer, (RecoveryScannerData)rootNode.getStatementsRecoveryData()); + rootNode.accept(visitor); + } + return result; + } + + private void markAsMoveOrCopyTarget(ASTNode node, ASTNode newChild) { + ASTNode source = (ASTNode)this.clonedNodes.get(newChild); + if(source != null) { + if(this.cloneDepth == 0) { + PropertyLocation propertyLocation = this.eventStore.getPropertyLocation(source, RewriteEventStore.ORIGINAL); + CopySourceInfo sourceInfo = + this.eventStore.markAsCopySource( + propertyLocation.getParent(), + propertyLocation.getProperty(), + source, + false); + this.nodeStore.markAsCopyTarget(newChild, sourceInfo); + } + } else if((newChild.getFlags() & ASTNode.ORIGINAL) != 0) { + PropertyLocation propertyLocation = this.eventStore.getPropertyLocation(newChild, RewriteEventStore.ORIGINAL); + CopySourceInfo sourceInfo = + this.eventStore.markAsCopySource( + propertyLocation.getParent(), + propertyLocation.getProperty(), + newChild, + true); + this.nodeStore.markAsCopyTarget(newChild, sourceInfo); + } + } + + private CompilationUnit getRootNode() { + return this.root; + } + + public String toString() { + StringBuffer buf = new StringBuffer(); + buf.append("Events:\n"); //$NON-NLS-1$ + buf.append(this.eventStore.toString()); + return buf.toString(); + } + + void preValueChangeEvent(ASTNode node, SimplePropertyDescriptor property) { + // force event creation + getNodeEvent(node, property); + } + + void postValueChangeEvent(ASTNode node, SimplePropertyDescriptor property) { + NodeRewriteEvent event = getNodeEvent(node, property); + event.setNewValue(node.getStructuralProperty(property)); + } + + void preAddChildEvent(ASTNode node, ASTNode child, StructuralPropertyDescriptor property) { + if(property.isChildProperty()) { + NodeRewriteEvent event = getNodeEvent(node, property); + event.setNewValue(child); + if(child != null) { + markAsMoveOrCopyTarget(node, child); + } + } else if(property.isChildListProperty()) { + // force event creation + getListEvent(node, property); + } + } + + void postAddChildEvent(ASTNode node, ASTNode child, StructuralPropertyDescriptor property) { + if(property.isChildListProperty()) { + + ListRewriteEvent event = getListEvent(node, property); + List list = (List)node.getStructuralProperty(property); + int i = list.indexOf(child); + int s = list.size(); + int index; + if(i + 1 < s) { + ASTNode nextNode = (ASTNode)list.get(i + 1); + index = event.getIndex(nextNode, ListRewriteEvent.NEW); + } else { + index = -1; + } + event.insert(child, index); + if(child != null) { + markAsMoveOrCopyTarget(node, child); + } + } + } + + void preRemoveChildEvent(ASTNode node, ASTNode child, StructuralPropertyDescriptor property) { + if(property.isChildProperty()) { + NodeRewriteEvent event = getNodeEvent(node, property); + event.setNewValue(null); + } else if(property.isChildListProperty()) { + ListRewriteEvent event = getListEvent(node, property); + int i = event.getIndex(child, ListRewriteEvent.NEW); + NodeRewriteEvent nodeEvent = (NodeRewriteEvent)event.getChildren()[i]; + if(nodeEvent.getOriginalValue() == null) { + event.revertChange(nodeEvent); + } else { + nodeEvent.setNewValue(null); + } + } + } + + void preReplaceChildEvent(ASTNode node, ASTNode child, ASTNode newChild, StructuralPropertyDescriptor property) { + if(property.isChildProperty()) { + NodeRewriteEvent event = getNodeEvent(node, property); + event.setNewValue(newChild); + if(newChild != null) { + markAsMoveOrCopyTarget(node, newChild); + } + } else if(property.isChildListProperty()) { + ListRewriteEvent event = getListEvent(node, property); + int i = event.getIndex(child, ListRewriteEvent.NEW); + NodeRewriteEvent nodeEvent = (NodeRewriteEvent)event.getChildren()[i]; + nodeEvent.setNewValue(newChild); + if(newChild != null) { + markAsMoveOrCopyTarget(node, newChild); + } + } + } + + + void preCloneNodeEvent(ASTNode node) { + this.cloneDepth++; + } + + + void postCloneNodeEvent(ASTNode node, ASTNode clone) { + if(node.ast == this.root.ast && clone.ast == this.root.ast) { + if((node.getFlags() & ASTNode.ORIGINAL) != 0) { + this.clonedNodes.put(clone, node); + } else { + // node can be a cloned node + Object original = this.clonedNodes.get(node); + if(original != null) { + this.clonedNodes.put(clone, original); + } + } + } + this.cloneDepth--; + } + + private NodeRewriteEvent getNodeEvent(ASTNode node, StructuralPropertyDescriptor property) { + return this.eventStore.getNodeEvent(node, property, true); + } + + private ListRewriteEvent getListEvent(ASTNode node, StructuralPropertyDescriptor property) { + return this.eventStore.getListEvent(node, property, true); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Javadoc.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Javadoc.java new file mode 100644 index 000000000..952039b0b --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Javadoc.java @@ -0,0 +1,320 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jdt.core.compiler.InvalidInputException; +import org.eclipse.jdt.internal.compiler.parser.Scanner; +import org.eclipse.jdt.internal.compiler.parser.TerminalTokens; + +/** + * AST node for a Javadoc-style doc comment. + * <pre> + * Javadoc: + * <b>/** </b> { TagElement } <b>*</b><b>/</b> + * </pre> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class Javadoc extends Comment { + + /** + * The "comment" structural property of this node type (JLS2 API only). + * @since 3.0 + * @deprecated Replaced by {@link #TAGS_PROPERTY} in the JLS3 API. + */ + public static final SimplePropertyDescriptor COMMENT_PROPERTY = + new SimplePropertyDescriptor(Javadoc.class, "comment", String.class, MANDATORY); //$NON-NLS-1$ + + /** + * The "tags" structural property of this node type. + * @since 3.1 + */ + public static final ChildListPropertyDescriptor TAGS_PROPERTY = + new ChildListPropertyDescriptor(Javadoc.class, "tags", TagElement.class, CYCLE_RISK); //$NON-NLS-1$ + + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + * @since 3.0 + */ + private static final List PROPERTY_DESCRIPTORS_2_0; + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + * @since 3.1 + */ + private static final List PROPERTY_DESCRIPTORS_3_0; + + static { + List properyList = new ArrayList(3); + createPropertyList(Javadoc.class, properyList); + addProperty(COMMENT_PROPERTY, properyList); + addProperty(TAGS_PROPERTY, properyList); + PROPERTY_DESCRIPTORS_2_0 = reapPropertyList(properyList); + + properyList = new ArrayList(2); + createPropertyList(Javadoc.class, properyList); + addProperty(TAGS_PROPERTY, properyList); + PROPERTY_DESCRIPTORS_3_0 = reapPropertyList(properyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + if (apiLevel == AST.JLS2_INTERNAL) { + return PROPERTY_DESCRIPTORS_2_0; + } else { + return PROPERTY_DESCRIPTORS_3_0; + } + } + + /** + * Canonical minimal doc comment. + * @since 3.0 + */ + private static final String MINIMAL_DOC_COMMENT = "/** */";//$NON-NLS-1$ + + /** + * The doc comment string, including opening and closing comment + * delimiters; defaults to a minimal Javadoc comment. + * @deprecated The comment string was replaced in the 3.0 release + * by a representation of the structure of the doc comment. + * For backwards compatibility, it is still funcational as before. + */ + private String comment = MINIMAL_DOC_COMMENT; + + /** + * The list of tag elements (element type: <code>TagElement</code>). + * Defaults to an empty list. + * @since 3.0 + */ + private ASTNode.NodeList tags = + new ASTNode.NodeList(TAGS_PROPERTY); + + /** + * Creates a new AST node for a doc comment owned by the given AST. + * The new node has an empty list of tag elements (and, for backwards + * compatability, an unspecified, but legal, doc comment string). + * <p> + * N.B. This constructor is package-private; all subclasses must be + * declared in the same package; clients are unable to declare + * additional subclasses. + * </p> + * + * @param ast the AST that is to own this node + */ + Javadoc(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final Object internalGetSetObjectProperty(SimplePropertyDescriptor property, boolean get, Object value) { + if (property == COMMENT_PROPERTY) { + if (get) { + return getComment(); + } else { + setComment((String) value); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetObjectProperty(property, get, value); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalGetChildListProperty(ChildListPropertyDescriptor property) { + if (property == TAGS_PROPERTY) { + return tags(); + } + // allow default implementation to flag the error + return super.internalGetChildListProperty(property); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return JAVADOC; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + Javadoc result = new Javadoc(target); + result.setSourceRange(getStartPosition(), getLength()); + if (this.ast.apiLevel == AST.JLS2_INTERNAL) { + result.setComment(getComment()); + } + result.tags().addAll(ASTNode.copySubtrees(target, tags())); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + acceptChildren(visitor, this.tags); + } + visitor.endVisit(this); + } + + /** + * Returns the doc comment string, including the starting + * and ending comment delimiters, and any embedded line breaks. + * + * @return the doc comment string + * @exception UnsupportedOperationException if this operation is used in + * an AST later than JLS2 + * @deprecated The comment string was replaced in the 3.0 release + * by a representation of the structure of the doc comment. + * See {@link #tags() tags}. + */ + public String getComment() { + supportedOnlyIn2(); + return this.comment; + } + + /** + * Sets or clears the doc comment string. The documentation + * string must include the starting and ending comment delimiters, + * and any embedded line breaks. + * + * @param docComment the doc comment string + * @exception IllegalArgumentException if the Java comment string is invalid + * @exception UnsupportedOperationException if this operation is used in + * an AST later than JLS2 + * @deprecated The comment string was replaced in the 3.0 release + * by a representation of the structure of the doc comment. + * See {@link #tags() tags}. + */ + public void setComment(String docComment) { + supportedOnlyIn2(); + if (docComment == null) { + throw new IllegalArgumentException(); + } + char[] source = docComment.toCharArray(); + Scanner scanner = this.ast.scanner; + scanner.resetTo(0, source.length); + scanner.setSource(source); + try { + int token; + boolean onlyOneComment = false; + while ((token = scanner.getNextToken()) != TerminalTokens.TokenNameEOF) { + switch(token) { + case TerminalTokens.TokenNameCOMMENT_JAVADOC : + if (onlyOneComment) { + throw new IllegalArgumentException(); + } + onlyOneComment = true; + break; + default: + onlyOneComment = false; + } + } + if (!onlyOneComment) { + throw new IllegalArgumentException(); + } + } catch (InvalidInputException e) { + throw new IllegalArgumentException(); + } + preValueChange(COMMENT_PROPERTY); + this.comment = docComment; + postValueChange(COMMENT_PROPERTY); + } + + /** + * Returns the live list of tag elements that make up this doc + * comment. + * <p> + * The tag elements cover everything except the starting and ending + * comment delimiters, and generally omit leading whitespace + * (including a leading "*") and embedded line breaks. + * The first tag element of a typical doc comment represents + * all the material before the first explicit doc tag; this + * first tag element has a <code>null</code> tag name and + * generally contains 1 or more {@link TextElement}s, + * and possibly interspersed with tag elements for nested tags + * like "{@link String String}". + * Subsequent tag elements represent successive top-level doc + * tag (e.g., "@param", "@return", "@see"). + * </p> + * <p> + * Adding and removing nodes from this list affects this node + * dynamically. + * </p> + * + * @return the live list of tag elements in this doc comment + * (element type: <code>TagElement</code>) + * @since 3.0 + */ + public List tags() { + return this.tags; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + int size = super.memSize() + 2 * 4; + if (this.comment != MINIMAL_DOC_COMMENT) { + // anything other than the default string takes space + size += stringSize(this.comment); + } + return size; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return memSize() + this.tags.listSize(); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/LabeledStatement.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/LabeledStatement.java new file mode 100644 index 000000000..b1e9c4c02 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/LabeledStatement.java @@ -0,0 +1,276 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Labeled statement AST node type. + * + * <pre> + * LabeledStatement: + * Identifier <b>:</b> Statement + * </pre> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class LabeledStatement extends Statement { + + /** + * The "label" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor LABEL_PROPERTY = + new ChildPropertyDescriptor(LabeledStatement.class, "label", SimpleName.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "body" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor BODY_PROPERTY = + new ChildPropertyDescriptor(LabeledStatement.class, "body", Statement.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List propertyList = new ArrayList(3); + createPropertyList(LabeledStatement.class, propertyList); + addProperty(LABEL_PROPERTY, propertyList); + addProperty(BODY_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The label; lazily initialized; defaults to a unspecified, + * legal Java identifier. + */ + private SimpleName labelName = null; + + /** + * The body statement; lazily initialized; defaults to an unspecified, but + * legal, statement. + */ + private Statement body = null; + + /** + * Creates a new AST node for a labeled statement owned by the given + * AST. By default, the statement has an unspecified (but legal) label + * and an unspecified (but legal) statement. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + LabeledStatement(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == LABEL_PROPERTY) { + if (get) { + return getLabel(); + } else { + setLabel((SimpleName) child); + return null; + } + } + if (property == BODY_PROPERTY) { + if (get) { + return getBody(); + } else { + setBody((Statement) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return LABELED_STATEMENT; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + LabeledStatement result = new LabeledStatement(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setLabel( + (SimpleName) ASTNode.copySubtree(target, getLabel())); + result.setBody( + (Statement) ASTNode.copySubtree(target, getBody())); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + acceptChild(visitor, getLabel()); + acceptChild(visitor, getBody()); + } + visitor.endVisit(this); + } + + /** + * Returns the label of this labeled statement. + * + * @return the variable name node + */ + public SimpleName getLabel() { + if (this.labelName == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.labelName == null) { + preLazyInit(); + this.labelName= new SimpleName(this.ast); + postLazyInit(this.labelName, LABEL_PROPERTY); + } + } + } + return this.labelName; + } + + /** + * Sets the label of this labeled statement. + * + * @param label the new label + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public void setLabel(SimpleName label) { + if (label == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.labelName; + preReplaceChild(oldChild, label, LABEL_PROPERTY); + this.labelName = label; + postReplaceChild(oldChild, label, LABEL_PROPERTY); + } + + /** + * Returns the body of this labeled statement. + * + * @return the body statement node + */ + public Statement getBody() { + if (this.body == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.body == null) { + preLazyInit(); + this.body= new EmptyStatement(this.ast); + postLazyInit(this.body, BODY_PROPERTY); + } + } + } + return this.body; + } + + /** + * Sets the body of this labeled statement. + * <p> + * Special note: The Java language does not allow a local variable declaration + * to appear as the body of a labeled statement (they may only appear within a + * block). However, the AST will allow a <code>VariableDeclarationStatement</code> + * as the body of a <code>LabeledStatement</code>. To get something that will + * compile, be sure to embed the <code>VariableDeclarationStatement</code> + * inside a <code>Block</code>. + * </p> + * + * @param statement the body statement node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setBody(Statement statement) { + if (statement == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.body; + preReplaceChild(oldChild, statement, BODY_PROPERTY); + this.body = statement; + postReplaceChild(oldChild, statement, BODY_PROPERTY); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return super.memSize() + 2 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.labelName == null ? 0 : getLabel().treeSize()) + + (this.body == null ? 0 : getBody().treeSize()); + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/LiftingType.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/LiftingType.java new file mode 100644 index 000000000..4a432c4a1 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/LiftingType.java @@ -0,0 +1,343 @@ +/********************************************************************** + * This file is part of "Object Teams Development Tooling"-Software + * + * Copyright 2004, 2006 Fraunhofer Gesellschaft, Munich, Germany, + * for its Fraunhofer Institute for Computer Architecture and Software + * Technology (FIRST), Berlin, Germany and Technical University Berlin, + * Germany. + * + * 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 + * $Id: LiftingType.java 23416 2010-02-03 19:59:31Z stephan $ + * + * Please visit http://www.eclipse.org/objectteams for updates and contact. + * + * Contributors: + * Fraunhofer FIRST - Initial API and implementation + * Technical University Berlin - Initial API and implementation + **********************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * NEW for OTDT + * + * Represents DOM-ASTNode for declared lifting (OTJLD §2.3.2) + * which has to handle code like: + * (MyClass as MyRole role) + * + * This class has following properties: + * Name + * baseType + * roleType + * + * This node represents a Type. + * + * This node inherits from Type and is handled like other types. + * - typically used in team level methods (declared lifting) + * + * @author jsv + */ + +public class LiftingType extends Type +{ + + /** + * The "BaseType" structural property of this node type. + */ + public static final ChildPropertyDescriptor BASE_TYPE_PROPERTY = + new ChildPropertyDescriptor(LiftingType.class, "baseType", Type.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "roleType" structural property of this node type. + */ + public static final ChildPropertyDescriptor ROLE_TYPE_PROPERTY = + new ChildPropertyDescriptor(LiftingType.class, "roleType", Type.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "name" structural property of this node type. + */ + public static final ChildPropertyDescriptor NAME_PROPERTY = + new ChildPropertyDescriptor(LiftingType.class, "name", Name.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static + { + List propertyList = new ArrayList(4); + createPropertyList(LiftingType.class, propertyList); + addProperty(NAME_PROPERTY, propertyList); + addProperty(BASE_TYPE_PROPERTY, propertyList); + addProperty(ROLE_TYPE_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + */ + public static List propertyDescriptors(int apiLevel) + { + return PROPERTY_DESCRIPTORS; + } + + /** + * The type name node; lazily initialized; defaults to a type with + * an unspecified, but legal, name. + */ + private Name typeName = null; + + /** + * The base type. + * JLS2 behevior: lazily initialized; defaults to void. + * Note that this field is ignored for constructor declarations. + */ + private Type _baseType = null; + + /** + * The role type. + * JLS2 behevior: lazily initialized; defaults to void. + * Note that this field is ignored for constructor declarations. + */ + private Type _roleType = null; + + /** + * Creates a new unparented node for a lifting type owned by the given AST. + * By default, an unspecified, but legal, name. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + LiftingType(AST ast) + { + super(ast); + } + + final List internalStructuralPropertiesForType(int apiLevel) + { + return propertyDescriptors(apiLevel); + } + + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) + { + if (property == NAME_PROPERTY) + { + if (get) + { + return getName(); + } + else + { + setName((Name) child); + return null; + } + } + + if (property == BASE_TYPE_PROPERTY) + { + if (get) + { + return getBaseType(); + } + else + { + setBaseType((Type) child); + return null; + } + } + + if (property == ROLE_TYPE_PROPERTY) + { + if (get) + { + return getRoleType(); + } + else + { + setRoleType((Type) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + final int getNodeType0() + { + return LIFTING_TYPE; + } + + ASTNode clone0(AST target) + { + LiftingType result = new LiftingType(target); + result.setSourceRange(this.getStartPosition(), this.getLength()); + result.setName((Name) (getName()).clone(target)); + result.setBaseType((Type) ASTNode.copySubtree(target, getBaseType())); + result.setRoleType((Type) ASTNode.copySubtree(target, getRoleType())); + + return result; + } + + final boolean subtreeMatch0(ASTMatcher matcher, Object other) + { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + void accept0(ASTVisitor visitor) + { + boolean visitChildren = visitor.visit(this); + if (visitChildren) + { + acceptChild(visitor, getName()); + acceptChild(visitor, getBaseType()); + acceptChild(visitor, getRoleType()); + } + visitor.endVisit(this); + } + + /** + * Returns the name of this lifting type. + * + * @return the name of this lifting type + */ + public Name getName() + { + if (this.typeName == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.typeName == null) { + preLazyInit(); + this.typeName = new SimpleName(this.ast); + postLazyInit(this.typeName, NAME_PROPERTY); + } + } + } + return this.typeName; + } + + /** + * Sets the name of this lifting type to the given name. + * + * @param typeName the new name of this lifting type + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public void setName(Name typeName) + { + if (typeName == null) + { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.typeName; + preReplaceChild(oldChild, typeName, NAME_PROPERTY); + this.typeName = typeName; + postReplaceChild(oldChild, typeName, NAME_PROPERTY); + } + + /** + * Returns the base type in this LiftingType, + */ + public Type getBaseType() + { + if (this._baseType == null) + { + // lazy init must be thread-safe for readers + synchronized (this) + { + if (this._baseType == null) + { + preLazyInit(); + this._baseType = this.ast.newPrimitiveType(PrimitiveType.VOID); + postLazyInit(this._baseType, BASE_TYPE_PROPERTY); + } + } + } + return this._baseType; + } + + /** + * Returns the role type in this LiftingType, + */ + public Type getRoleType() + { + if (this._roleType == null) + { + // lazy init must be thread-safe for readers + synchronized (this) + { + if (this._roleType == null) + { + preLazyInit(); + this._roleType = this.ast.newPrimitiveType(PrimitiveType.VOID); + postLazyInit(this._roleType, ROLE_TYPE_PROPERTY); + } + } + } + return this._roleType; + } + + /** + * Sets the base type of in this LiftingType + */ + public void setBaseType(Type type) + { + if (type == null) + { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this._baseType; + preReplaceChild(oldChild, type, BASE_TYPE_PROPERTY); + this._baseType = type; + postReplaceChild(oldChild, type, BASE_TYPE_PROPERTY); + } + + /** + * Sets the role type of in this LiftingType + */ + public void setRoleType(Type type) + { + if (type == null) + { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this._roleType; + preReplaceChild(oldChild, type, ROLE_TYPE_PROPERTY); + this._roleType = type; + postReplaceChild(oldChild, type, ROLE_TYPE_PROPERTY); + } + + int memSize() + { + // treat Code as free + return BASE_NODE_SIZE + 3 * 4; + } + + int treeSize() + { + return memSize() + + (this.typeName == null ? 0 : getName().treeSize()) + + (this.getBaseType() == null ? 0 : getBaseType().treeSize()) + + (this.getRoleType() == null ? 0 : getRoleType().treeSize()); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/LineComment.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/LineComment.java new file mode 100644 index 000000000..d1f73ef69 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/LineComment.java @@ -0,0 +1,127 @@ +/******************************************************************************* + * Copyright (c) 2004, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * End-of-line comment AST node type. + * <p> + * End-of-line comments begin with "//", + * must end with a line delimiter (as per JLS 3.7), + * and must not contain line breaks. + * </p> + * <p> + * Note that this node type is a comment placeholder, and is + * only useful for recording the source range where a comment + * was found in a source string. It is not useful for creating + * comments. + * </p> + * + * @since 3.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public final class LineComment extends Comment { + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List propertyList = new ArrayList(1); + createPropertyList(LineComment.class, propertyList); + PROPERTY_DESCRIPTORS = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * Creates a new line comment node owned by the given AST. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + LineComment(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return LINE_COMMENT; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + LineComment result = new LineComment(target); + result.setSourceRange(getStartPosition(), getLength()); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + visitor.visit(this); + visitor.endVisit(this); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return super.memSize(); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return memSize(); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MarkerAnnotation.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MarkerAnnotation.java new file mode 100644 index 000000000..46e303fd6 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MarkerAnnotation.java @@ -0,0 +1,160 @@ +/******************************************************************************* + * Copyright (c) 2004, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Marker annotation node (added in JLS3 API). The marker annotation + * "@foo" is equivalent to the normal annotation "@foo()". + * <p> + * <pre> + * MarkerAnnotation: + * <b>@</b> TypeName + * </pre> + * </p> + * + * @since 3.1 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public final class MarkerAnnotation extends Annotation { + + /** + * The "typeName" structural property of this node type. + */ + public static final ChildPropertyDescriptor TYPE_NAME_PROPERTY = + internalTypeNamePropertyFactory(MarkerAnnotation.class); + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List propertyList = new ArrayList(2); + createPropertyList(MarkerAnnotation.class, propertyList); + addProperty(TYPE_NAME_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the AST.JLS* constants + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * Creates a new unparented marker annotation node owned + * by the given AST. By default, the annotation has an + * unspecified type name . + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + MarkerAnnotation(AST ast) { + super(ast); + unsupportedIn2(); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == TYPE_NAME_PROPERTY) { + if (get) { + return getTypeName(); + } else { + setTypeName((Name) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on BodyDeclaration. + */ + final ChildPropertyDescriptor internalTypeNameProperty() { + return TYPE_NAME_PROPERTY; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return MARKER_ANNOTATION; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + MarkerAnnotation result = new MarkerAnnotation(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setTypeName((Name) ASTNode.copySubtree(target, getTypeName())); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + acceptChild(visitor, getTypeName()); + } + visitor.endVisit(this); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return super.memSize(); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.typeName == null ? 0 : getTypeName().treeSize()); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MemberRef.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MemberRef.java new file mode 100644 index 000000000..da4d55b19 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MemberRef.java @@ -0,0 +1,272 @@ +/******************************************************************************* + * Copyright (c) 2004, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * AST node for a member reference within a doc comment + * ({@link Javadoc}). The principal uses of these are in "@see" and "@link" + * tag elements, for references to field members (and occasionally to method + * and constructor members). + * <pre> + * MemberRef: + * [ Name ] <b>#</b> Identifier + * </pre> + * + * @see Javadoc + * @since 3.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class MemberRef extends ASTNode implements IDocElement { + + /** + * The "qualifier" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor QUALIFIER_PROPERTY = + new ChildPropertyDescriptor(MemberRef.class, "qualifier", Name.class, OPTIONAL, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "name" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor NAME_PROPERTY = + new ChildPropertyDescriptor(MemberRef.class, "name", SimpleName.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List propertyList = new ArrayList(3); + createPropertyList(MemberRef.class, propertyList); + addProperty(QUALIFIER_PROPERTY, propertyList); + addProperty(NAME_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the AST.JLS* constants + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The optional qualifier; <code>null</code> for none; defaults to none. + */ + private Name optionalQualifier = null; + + /** + * The member name; lazily initialized; defaults to a unspecified, + * legal Java method name. + */ + private SimpleName memberName = null; + + /** + * Creates a new AST node for a member reference owned by the given + * AST. By default, the method reference is for a member with an + * unspecified, but legal, name; and no qualifier. + * <p> + * N.B. This constructor is package-private; all subclasses must be + * declared in the same package; clients are unable to declare + * additional subclasses. + * </p> + * + * @param ast the AST that is to own this node + */ + MemberRef(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == QUALIFIER_PROPERTY) { + if (get) { + return getQualifier(); + } else { + setQualifier((Name) child); + return null; + } + } + if (property == NAME_PROPERTY) { + if (get) { + return getName(); + } else { + setName((SimpleName) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return MEMBER_REF; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + MemberRef result = new MemberRef(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setQualifier((Name) ASTNode.copySubtree(target, getQualifier())); + result.setName((SimpleName) ASTNode.copySubtree(target, getName())); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + acceptChild(visitor, getQualifier()); + acceptChild(visitor, getName()); + } + visitor.endVisit(this); + } + + /** + * Returns the qualifier of this member reference, or + * <code>null</code> if there is none. + * + * @return the qualifier name node, or <code>null</code> if there is none + */ + public Name getQualifier() { + return this.optionalQualifier; + } + + /** + * Sets or clears the qualifier of this member reference. + * + * @param name the qualifier name node, or <code>null</code> if + * there is none + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public void setQualifier(Name name) { + ASTNode oldChild = this.optionalQualifier; + preReplaceChild(oldChild, name, QUALIFIER_PROPERTY); + this.optionalQualifier = name; + postReplaceChild(oldChild, name, QUALIFIER_PROPERTY); + } + + /** + * Returns the name of the referenced member. + * + * @return the member name node + */ + public SimpleName getName() { + if (this.memberName == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.memberName == null) { + preLazyInit(); + this.memberName = new SimpleName(this.ast); + postLazyInit(this.memberName, NAME_PROPERTY); + } + } + } + return this.memberName; + } + + /** + * Sets the name of the referenced member to the given name. + * + * @param name the new member name node + * @exception IllegalArgumentException if: + * <ul> + * <li>the name is <code>null</code></li> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public void setName(SimpleName name) { + if (name == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.memberName; + preReplaceChild(oldChild, name, NAME_PROPERTY); + this.memberName = name; + postReplaceChild(oldChild, name, NAME_PROPERTY); + } + + /** + * Resolves and returns the binding for the entity referred to by + * this member reference. + * <p> + * Note that bindings are generally unavailable unless requested when the + * AST is being built. + * </p> + * + * @return the binding, or <code>null</code> if the binding cannot be + * resolved + */ + public final IBinding resolveBinding() { + return this.ast.getBindingResolver().resolveReference(this); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return BASE_NODE_SIZE + 2 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.optionalQualifier == null ? 0 : getQualifier().treeSize()) + + (this.memberName == null ? 0 : getName().treeSize()); + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MemberValuePair.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MemberValuePair.java new file mode 100644 index 000000000..fcf231904 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MemberValuePair.java @@ -0,0 +1,280 @@ +/******************************************************************************* + * Copyright (c) 2004, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Member value pair node (added in JLS3 API). Member value pairs appear in annotations. + * <p> + * <pre> + * MemberValuePair: + * SimpleName <b>=</b> Expression + * </pre> + * Within annotations, only certain kinds of expressions are meaningful, + * including other annotations. + * </p> + * + * @see NormalAnnotation + * @since 3.1 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class MemberValuePair extends ASTNode { + + /** + * The "name" structural property of this node type. + */ + public static final ChildPropertyDescriptor NAME_PROPERTY = + new ChildPropertyDescriptor(MemberValuePair.class, "name", SimpleName.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "value" structural property of this node type. + */ + public static final ChildPropertyDescriptor VALUE_PROPERTY = + new ChildPropertyDescriptor(MemberValuePair.class, "value", Expression.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List propertyList = new ArrayList(3); + createPropertyList(MemberValuePair.class, propertyList); + addProperty(NAME_PROPERTY, propertyList); + addProperty(VALUE_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the AST.JLS* constants + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The member name; lazily initialized; defaults to a unspecified, + * legal name. + */ + private SimpleName name = null; + + /** + * The value; lazily initialized; defaults to a unspecified, + * legal expression. + */ + private Expression value = null; + + /** + * Creates a new AST node for a member value pair owned by the given + * AST. By default, the node has an unspecified (but legal) member + * name and value. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + MemberValuePair(AST ast) { + super(ast); + unsupportedIn2(); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == NAME_PROPERTY) { + if (get) { + return getName(); + } else { + setName((SimpleName) child); + return null; + } + } + if (property == VALUE_PROPERTY) { + if (get) { + return getValue(); + } else { + setValue((Expression) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return MEMBER_VALUE_PAIR; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + MemberValuePair result = new MemberValuePair(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setName((SimpleName) ASTNode.copySubtree(target, getName())); + result.setValue((Expression) ASTNode.copySubtree(target, getValue())); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + acceptChild(visitor, getName()); + acceptChild(visitor, getValue()); + } + visitor.endVisit(this); + } + + /** + * Returns the member name. + * + * @return the member name node + */ + public SimpleName getName() { + if (this.name == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.name == null) { + preLazyInit(); + this.name = new SimpleName(this.ast); + postLazyInit(this.name, NAME_PROPERTY); + } + } + } + return this.name; + } + + /** + * Resolves and returns the member value pair binding for this member value pair. + * <p> + * Note that bindings are generally unavailable unless requested when the + * AST is being built. + * </p> + * + * @return the binding, or <code>null</code> if the binding cannot be + * resolved + * @since 3.2 + */ + public final IMemberValuePairBinding resolveMemberValuePairBinding() { + return this.ast.getBindingResolver().resolveMemberValuePair(this); + } + + /** + * Sets the member name. + * + * @param name the member name node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public void setName(SimpleName name) { + if (name == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.name; + preReplaceChild(oldChild, name, NAME_PROPERTY); + this.name = name; + postReplaceChild(oldChild, name, NAME_PROPERTY); + } + + /** + * Returns the value expression. + * + * @return the value expression + */ + public Expression getValue() { + if (this.value == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.value == null) { + preLazyInit(); + this.value= new SimpleName(this.ast); + postLazyInit(this.value, VALUE_PROPERTY); + } + } + } + return this.value; + } + + /** + * Sets the value of this pair. + * + * @param value the new value + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setValue(Expression value) { + if (value == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.value; + preReplaceChild(oldChild, value, VALUE_PROPERTY); + this.value = value; + postReplaceChild(oldChild, value, VALUE_PROPERTY); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return BASE_NODE_SIZE + 2 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.name == null ? 0 : getName().treeSize()) + + (this.value == null ? 0 : getValue().treeSize()); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MemberValuePairBinding.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MemberValuePairBinding.java new file mode 100644 index 000000000..6f2c13bb3 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MemberValuePairBinding.java @@ -0,0 +1,208 @@ +/******************************************************************************* + * Copyright (c) 2005, 2009 BEA Systems, Inc. + * 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: + * tyeung@bea.com - initial API and implementation + * IBM Corporation - implemented methods from IBinding + * IBM Corporation - renamed from ResolvedMemberValuePair to MemberValuePairBinding + * jgarms@bea.com - Fix for IllegalStateException + *******************************************************************************/ +package org.eclipse.jdt.core.dom; + +import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.internal.compiler.impl.Constant; +import org.eclipse.jdt.internal.compiler.lookup.ElementValuePair; +import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; +import org.eclipse.jdt.internal.compiler.lookup.TypeIds; + +/** + * Internal class. + */ +class MemberValuePairBinding implements IMemberValuePairBinding { + static final MemberValuePairBinding[] NoPair = new MemberValuePairBinding[0]; + private static final Object NoValue = new Object(); + private static final Object[] EmptyArray = new Object[0]; + + private ElementValuePair internalPair; + protected Object value = null; + protected BindingResolver bindingResolver; + + static void appendValue(Object value, StringBuffer buffer) { + if (value instanceof Object[]) { + Object[] values = (Object[]) value; + buffer.append('{'); + for (int i = 0, l = values.length; i < l; i++) { + if (i != 0) + buffer.append(", "); //$NON-NLS-1$ + appendValue(values[i], buffer); + } + buffer.append('}'); + } else if (value instanceof ITypeBinding) { + buffer.append(((ITypeBinding) value).getName()); + buffer.append(".class"); //$NON-NLS-1$ + } else { + buffer.append(value); + } + } + + static Object buildDOMValue(final Object internalObject, BindingResolver resolver) { + if (internalObject == null) + return null; + + if (internalObject instanceof Constant) { + Constant constant = (Constant) internalObject; + switch (constant.typeID()) { + case TypeIds.T_boolean: + return Boolean.valueOf(constant.booleanValue()); + case TypeIds.T_byte: + return new Byte(constant.byteValue()); + case TypeIds.T_char: + return new Character(constant.charValue()); + case TypeIds.T_double: + return new Double(constant.doubleValue()); + case TypeIds.T_float: + return new Float(constant.floatValue()); + case TypeIds.T_int: + return new Integer(constant.intValue()); + case TypeIds.T_long: + return new Long(constant.longValue()); + case TypeIds.T_short: + return new Short(constant.shortValue()); + case TypeIds.T_JavaLangString: + return constant.stringValue(); + } + } else if (internalObject instanceof org.eclipse.jdt.internal.compiler.lookup.TypeBinding) { + return resolver.getTypeBinding((org.eclipse.jdt.internal.compiler.lookup.TypeBinding) internalObject); + } else if (internalObject instanceof org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding) { + return resolver.getAnnotationInstance((org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding) internalObject); + } else if (internalObject instanceof org.eclipse.jdt.internal.compiler.lookup.FieldBinding) { + return resolver.getVariableBinding((org.eclipse.jdt.internal.compiler.lookup.FieldBinding) internalObject); + } else if (internalObject instanceof Object[]) { + Object[] elements = (Object[]) internalObject; + int length = elements.length; + Object[] values = length == 0 ? EmptyArray : new Object[length]; + for (int i = 0; i < length; i++) + values[i] = buildDOMValue(elements[i], resolver); + return values; + } + return null; + } + + MemberValuePairBinding(ElementValuePair pair, BindingResolver resolver) { + this.internalPair = pair; + this.bindingResolver = resolver; + } + + public IAnnotationBinding[] getAnnotations() { + return AnnotationBinding.NoAnnotations; + } + + public IJavaElement getJavaElement() { + return null; + } + + public String getKey() { + // TODO when implementing, update spec in IBinding + return null; + } + + public int getKind() { + return IBinding.MEMBER_VALUE_PAIR; + } + + public IMethodBinding getMethodBinding() { + return this.bindingResolver.getMethodBinding(this.internalPair.getMethodBinding()); + } + + public int getModifiers() { + return Modifier.NONE; + } + + public String getName() { + if (this.internalPair == null) + return null; + final char[] membername = this.internalPair.getName(); + return membername == null ? null : new String(membername); + } + + public Object getValue() { + if (this.value == null) + init(); + return this.value == NoValue ? null : this.value; + } + + private void init() { + this.value = buildDOMValue(this.internalPair.getValue(), this.bindingResolver); + if (this.value == null) + this.value = NoValue; + } + + char[] internalName() { + return this.internalPair == null ? null : this.internalPair.getName(); + } + + public boolean isDefault() { + Object value2 = getValue(); + Object defaultValue = getMethodBinding().getDefaultValue(); + if (value2 instanceof IBinding) { + if (defaultValue instanceof IBinding) { + return ((IBinding) value2).isEqualTo((IBinding) defaultValue); + } + return false; + } + if (defaultValue == null) return false; + return defaultValue.equals(value2); + } + + public boolean isDeprecated() { + MethodBinding methodBinding = this.internalPair.getMethodBinding(); + return methodBinding == null ? false : methodBinding.isDeprecated(); + } + + public boolean isEqualTo(IBinding binding) { + if (this == binding) + return true; + if (binding.getKind() != IBinding.MEMBER_VALUE_PAIR) + return false; + IMemberValuePairBinding other = (IMemberValuePairBinding) binding; + if (!getMethodBinding().isEqualTo(other.getMethodBinding())) { + return false; + } + Object otherValue = other.getValue(); + Object currentValue = getValue(); + if (currentValue == null) { + return otherValue == null; + } + if (currentValue instanceof IBinding) { + if (otherValue instanceof IBinding) { + return ((IBinding) currentValue).isEqualTo((IBinding) otherValue); + } + return false; + } + return currentValue.equals(otherValue); + } + + /* + * (non-Javadoc) + * @see org.eclipse.jdt.core.dom.IBinding#isRecovered() + */ + public boolean isRecovered() { + return false; + } + + public boolean isSynthetic() { + return false; + } + + public String toString() { + StringBuffer buffer = new StringBuffer(); + buffer.append(getName()); + buffer.append(" = "); //$NON-NLS-1$ + appendValue(getValue(), buffer); + return buffer.toString(); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Message.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Message.java new file mode 100644 index 000000000..998cb8e11 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Message.java @@ -0,0 +1,134 @@ +/******************************************************************************* + * Copyright (c) 2000, 2009 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +/** + * Error message used to report potential errors found during the AST parsing + * or name resolution. Instances of this class are immutable. + * + * @since 2.0 + */ +public class Message { + + /** + * The message. + */ + private String message; + + /** + * The character index into the original source string, or -1 if none. + */ + private int startPosition; + + /** + * The length in characters of the original source file indicating + * where the source fragment corresponding to this message ends. + */ + private int length; + + /** + * Creates a message. + * + * @param message the localized message reported by the compiler + * @param startPosition the 0-based character index into the + * original source file, or <code>-1</code> if no source position + * information is to be recorded for this message + * @throws IllegalArgumentException if the message is null + * @throws IllegalArgumentException if the startPosition is lower than -1. + */ + public Message(String message, int startPosition) { + if (message == null) { + throw new IllegalArgumentException(); + } + if (startPosition < -1) { + throw new IllegalArgumentException(); + } + this.message = message; + this.startPosition = startPosition; + this.length = 0; + } + + /** + * Creates a message. + * + * @param message the localized message reported by the compiler + * @param startPosition the 0-based character index into the + * original source file, or <code>-1</code> if no source position + * information is to be recorded for this message + * @param length the length in character of the original source file indicating + * where the source fragment corresponding to this message ends. 0 or a negative number + * if none. A negative number will be converted to a 0-length. + * @throws IllegalArgumentException if the message is null + * @throws IllegalArgumentException if the startPosition is lower than -1. + */ + public Message(String message, int startPosition, int length) { + if (message == null) { + throw new IllegalArgumentException(); + } + if (startPosition < -1) { + throw new IllegalArgumentException(); + } + this.message = message; + this.startPosition = startPosition; + if (length <= 0) { + this.length = 0; + } else { + this.length = length; + } + } + + /** + * Returns the localized message. + * + * @return the localized message + */ + public String getMessage() { + return this.message; + } + + /** + * Returns the character index into the original source file. + * + * @return the 0-based character index, or <code>-1</code> + * if no source position information is recorded for this + * message + * @deprecated Use {@link #getStartPosition()} instead. + * @see #getLength() + */ + public int getSourcePosition() { + return getStartPosition(); + } + + /** + * Returns the character index into the original source file. + * + * @return the 0-based character index, or <code>-1</code> + * if no source position information is recorded for this + * message + * @see #getLength() + */ + public int getStartPosition() { + return this.startPosition; + } + + /** + * Returns the length in characters of the original source file indicating + * where the source fragment corresponding to this message ends. + * + * @return a length, or <code>0</code> + * if no source length information is recorded for this message + * @see #getStartPosition() + */ + public int getLength() { + return this.length; + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodBinding.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodBinding.java new file mode 100644 index 000000000..d3cb6df8d --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodBinding.java @@ -0,0 +1,473 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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 + * $Id: MethodBinding.java 23404 2010-02-03 14:10:22Z stephan $ + * + * Contributors: + * IBM Corporation - initial API and implementation + * Fraunhofer FIRST - extended API and implementation + * Technical University Berlin - extended API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers; +import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment; +import org.eclipse.jdt.internal.compiler.lookup.ParameterizedGenericMethodBinding; +import org.eclipse.jdt.internal.compiler.lookup.RawTypeBinding; +import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; +import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; +import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding; +import org.eclipse.jdt.internal.compiler.problem.AbortCompilation; +import org.eclipse.jdt.internal.core.JavaElement; +import org.eclipse.jdt.internal.core.util.Util; +import org.eclipse.objectteams.otdt.internal.core.compiler.model.MethodModel; +import org.eclipse.objectteams.otdt.internal.core.compiler.statemachine.transformer.MethodSignatureEnhancer; + +/** + * Internal implementation of method bindings. + */ +class MethodBinding implements IMethodBinding { + + private static final int VALID_MODIFIERS = Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE | +//{ObjectTeams: callin: + Modifier.OT_CALLIN | +// SH} + Modifier.ABSTRACT | Modifier.STATIC | Modifier.FINAL | Modifier.SYNCHRONIZED | Modifier.NATIVE | + Modifier.STRICTFP; + private static final ITypeBinding[] NO_TYPE_BINDINGS = new ITypeBinding[0]; + private org.eclipse.jdt.internal.compiler.lookup.MethodBinding binding; + private BindingResolver resolver; + private ITypeBinding[] parameterTypes; + private ITypeBinding[] exceptionTypes; + private String name; + private ITypeBinding declaringClass; + private ITypeBinding returnType; + private String key; + private ITypeBinding[] typeParameters; + private ITypeBinding[] typeArguments; + private IAnnotationBinding[] annotations; + private IAnnotationBinding[][] parameterAnnotations; + + MethodBinding(BindingResolver resolver, org.eclipse.jdt.internal.compiler.lookup.MethodBinding binding) { + this.resolver = resolver; + this.binding = binding; + } + + public boolean isAnnotationMember() { + return getDeclaringClass().isAnnotation(); + } + + /** + * @see IMethodBinding#isConstructor() + */ + public boolean isConstructor() { + return this.binding.isConstructor(); + } + + /** + * @see IMethodBinding#isDefaultConstructor() + * @since 3.0 + */ + public boolean isDefaultConstructor() { + final ReferenceBinding declaringClassBinding = this.binding.declaringClass; + if (declaringClassBinding.isRawType()) { + RawTypeBinding rawTypeBinding = (RawTypeBinding) declaringClassBinding; + if (rawTypeBinding.genericType().isBinaryBinding()) { + return false; + } + return (this.binding.modifiers & ExtraCompilerModifiers.AccIsDefaultConstructor) != 0; + } + if (declaringClassBinding.isBinaryBinding()) { + return false; + } + return (this.binding.modifiers & ExtraCompilerModifiers.AccIsDefaultConstructor) != 0; + } + + /** + * @see IBinding#getName() + */ + public String getName() { + if (this.name == null) { + if (this.binding.isConstructor()) { + this.name = getDeclaringClass().getName(); + } else { + this.name = new String(this.binding.selector); + } + } + return this.name; + } + + public IAnnotationBinding[] getAnnotations() { + if (this.annotations != null) { + return this.annotations; + } + org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding[] internalAnnotations = this.binding.getAnnotations(); + int length = internalAnnotations == null ? 0 : internalAnnotations.length; + if (length != 0) { + IAnnotationBinding[] tempAnnotations = new IAnnotationBinding[length]; + int convertedAnnotationCount = 0; + for (int i = 0; i < length; i++) { + org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding internalAnnotation = internalAnnotations[i]; + final IAnnotationBinding annotationInstance = this.resolver.getAnnotationInstance(internalAnnotation); + if (annotationInstance == null) { + continue; + } + tempAnnotations[convertedAnnotationCount++] = annotationInstance; + } + if (convertedAnnotationCount != length) { + if (convertedAnnotationCount == 0) { + return this.annotations = AnnotationBinding.NoAnnotations; + } + System.arraycopy(tempAnnotations, 0, (tempAnnotations = new IAnnotationBinding[convertedAnnotationCount]), 0, convertedAnnotationCount); + } + return this.annotations = tempAnnotations; + } + return this.annotations = AnnotationBinding.NoAnnotations; + } + + /** + * @see IMethodBinding#getDeclaringClass() + */ + public ITypeBinding getDeclaringClass() { + if (this.declaringClass == null) { +//{ObjectTeams: a role-ifc-method representing a one that is inherited from a non-role? + if (this.binding.copyInheritanceSrc != null) + { + this.declaringClass = this.resolver.getTypeBinding(this.binding.copyInheritanceSrc.declaringClass); + if (!this.declaringClass.isRole()) + return this.declaringClass; + } +// SH} + this.declaringClass = this.resolver.getTypeBinding(this.binding.declaringClass); + } + return this.declaringClass; + } + + public IAnnotationBinding[] getParameterAnnotations(int index) { + if (getParameterTypes() == NO_TYPE_BINDINGS) { + return AnnotationBinding.NoAnnotations; + } + if (this.parameterAnnotations != null) { + return this.parameterAnnotations[index]; + } + org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding[][] bindingAnnotations = this.binding.getParameterAnnotations(); + if (bindingAnnotations == null) return AnnotationBinding.NoAnnotations; + + int length = bindingAnnotations.length; + IAnnotationBinding[][] domAnnotations = new IAnnotationBinding[length][]; + for (int i = 0; i < length; i++) { + org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding[] paramBindingAnnotations = bindingAnnotations[i]; + int pLength = paramBindingAnnotations.length; + domAnnotations[i] = new AnnotationBinding[pLength]; + for (int j=0; j<pLength; j++) { + IAnnotationBinding domAnnotation = this.resolver.getAnnotationInstance(paramBindingAnnotations[j]); + if (domAnnotation == null) { + domAnnotations[i] = AnnotationBinding.NoAnnotations; + break; + } + domAnnotations[i][j] = domAnnotation; + } + } + this.parameterAnnotations = domAnnotations; + + return this.parameterAnnotations[index]; + } + + /** + * @see IMethodBinding#getParameterTypes() + */ + public ITypeBinding[] getParameterTypes() { + if (this.parameterTypes != null) { + return this.parameterTypes; + } + org.eclipse.jdt.internal.compiler.lookup.TypeBinding[] parameters = this.binding.parameters; +//{ObjectTeams: retrench callin method: + if ((this.getModifiers() & ExtraCompilerModifiers.AccCallin) != 0) + parameters = MethodSignatureEnhancer.retrenchParameterTypes(parameters); +// SH} + int length = parameters == null ? 0 : parameters.length; + if (length == 0) { + return this.parameterTypes = NO_TYPE_BINDINGS; + } else { + ITypeBinding[] paramTypes = new ITypeBinding[length]; + for (int i = 0; i < length; i++) { + final TypeBinding parameterBinding = parameters[i]; + if (parameterBinding != null) { + ITypeBinding typeBinding = this.resolver.getTypeBinding(parameterBinding); + if (typeBinding == null) { + return this.parameterTypes = NO_TYPE_BINDINGS; + } + paramTypes[i] = typeBinding; + } else { + // log error + StringBuffer message = new StringBuffer("Report method binding where a parameter is null:\n"); //$NON-NLS-1$ + message.append(toString()); + Util.log(new IllegalArgumentException(), message.toString()); + // report no binding since one or more parameter has no binding + return this.parameterTypes = NO_TYPE_BINDINGS; + } + } + return this.parameterTypes = paramTypes; + } + } + + /** + * @see IMethodBinding#getReturnType() + */ + public ITypeBinding getReturnType() { + if (this.returnType == null) { +//{ObjectTeams: retrench callin method: + if ((this.getModifiers() & ExtraCompilerModifiers.AccCallin) != 0) { + TypeBinding realReturnType = MethodModel.getReturnType(this.binding); + this.returnType = this.resolver.getTypeBinding(realReturnType); + } else +// SH} + this.returnType = this.resolver.getTypeBinding(this.binding.returnType); + } + return this.returnType; + } + + public Object getDefaultValue() { + if (isAnnotationMember()) + return MemberValuePairBinding.buildDOMValue(this.binding.getDefaultValue(), this.resolver); + return null; + } + + /** + * @see IMethodBinding#getExceptionTypes() + */ + public ITypeBinding[] getExceptionTypes() { + if (this.exceptionTypes != null) { + return this.exceptionTypes; + } + org.eclipse.jdt.internal.compiler.lookup.TypeBinding[] exceptions = this.binding.thrownExceptions; + int length = exceptions == null ? 0 : exceptions.length; + if (length == 0) { + return this.exceptionTypes = NO_TYPE_BINDINGS; + } + ITypeBinding[] exTypes = new ITypeBinding[length]; + for (int i = 0; i < length; i++) { + ITypeBinding typeBinding = this.resolver.getTypeBinding(exceptions[i]); + if (typeBinding == null) { + return this.exceptionTypes = NO_TYPE_BINDINGS; + } + exTypes[i] = typeBinding; + } + return this.exceptionTypes = exTypes; + } + + public IJavaElement getJavaElement() { + JavaElement element = getUnresolvedJavaElement(); + if (element == null) + return null; + return element.resolved(this.binding); + } + + private JavaElement getUnresolvedJavaElement() { + if (!(this.resolver instanceof DefaultBindingResolver)) return null; + + DefaultBindingResolver defaultBindingResolver = (DefaultBindingResolver) this.resolver; + return Util.getUnresolvedJavaElement( + this.binding, + defaultBindingResolver.workingCopyOwner, + defaultBindingResolver.getBindingsToNodesMap()); + } + + /** + * @see IBinding#getKind() + */ + public int getKind() { + return IBinding.METHOD; + } + + /** + * @see IBinding#getModifiers() + */ + public int getModifiers() { + return this.binding.getAccessFlags() & VALID_MODIFIERS; + } + + /** + * @see IBinding#isDeprecated() + */ + public boolean isDeprecated() { + return this.binding.isDeprecated(); + } + + /** + * @see IBinding#isRecovered() + */ + public boolean isRecovered() { + return false; + } + + /** + * @see IBinding#isSynthetic() + */ + public boolean isSynthetic() { + return this.binding.isSynthetic(); + } + + /** + * @see org.eclipse.jdt.core.dom.IMethodBinding#isVarargs() + * @since 3.1 + */ + public boolean isVarargs() { + return this.binding.isVarargs(); + } + + /** + * @see IBinding#getKey() + */ + public String getKey() { + if (this.key == null) { + this.key = new String(this.binding.computeUniqueKey()); + } + return this.key; + } + + /** + * @see IBinding#isEqualTo(IBinding) + * @since 3.1 + */ + public boolean isEqualTo(IBinding other) { + if (other == this) { + // identical binding - equal (key or no key) + return true; + } + if (other == null) { + // other binding missing + return false; + } + if (!(other instanceof MethodBinding)) { + return false; + } + org.eclipse.jdt.internal.compiler.lookup.MethodBinding otherBinding = ((MethodBinding) other).binding; + return BindingComparator.isEqual(this.binding, otherBinding); + } + + /** + * @see org.eclipse.jdt.core.dom.IMethodBinding#getTypeParameters() + */ + public ITypeBinding[] getTypeParameters() { + if (this.typeParameters != null) { + return this.typeParameters; + } + TypeVariableBinding[] typeVariableBindings = this.binding.typeVariables(); + int typeVariableBindingsLength = typeVariableBindings == null ? 0 : typeVariableBindings.length; + if (typeVariableBindingsLength == 0) { + return this.typeParameters = NO_TYPE_BINDINGS; + } + ITypeBinding[] tParameters = new ITypeBinding[typeVariableBindingsLength]; + for (int i = 0; i < typeVariableBindingsLength; i++) { + ITypeBinding typeBinding = this.resolver.getTypeBinding(typeVariableBindings[i]); + if (typeBinding == null) { + return this.typeParameters = NO_TYPE_BINDINGS; + } + tParameters[i] = typeBinding; + } + return this.typeParameters = tParameters; + } + + /** + * @see org.eclipse.jdt.core.dom.IMethodBinding#isGenericMethod() + * @since 3.1 + */ + public boolean isGenericMethod() { + // equivalent to return getTypeParameters().length > 0; + if (this.typeParameters != null) { + return this.typeParameters.length > 0; + } + TypeVariableBinding[] typeVariableBindings = this.binding.typeVariables(); + return (typeVariableBindings != null && typeVariableBindings.length > 0); + } + + /** + * @see org.eclipse.jdt.core.dom.IMethodBinding#getTypeArguments() + */ + public ITypeBinding[] getTypeArguments() { + if (this.typeArguments != null) { + return this.typeArguments; + } + + if (this.binding instanceof ParameterizedGenericMethodBinding) { + ParameterizedGenericMethodBinding genericMethodBinding = (ParameterizedGenericMethodBinding) this.binding; + org.eclipse.jdt.internal.compiler.lookup.TypeBinding[] typeArgumentsBindings = genericMethodBinding.typeArguments; + int typeArgumentsLength = typeArgumentsBindings == null ? 0 : typeArgumentsBindings.length; + if (typeArgumentsLength != 0) { + ITypeBinding[] tArguments = new ITypeBinding[typeArgumentsLength]; + for (int i = 0; i < typeArgumentsLength; i++) { + ITypeBinding typeBinding = this.resolver.getTypeBinding(typeArgumentsBindings[i]); + if (typeBinding == null) { + return this.typeArguments = NO_TYPE_BINDINGS; + } + tArguments[i] = typeBinding; + } + return this.typeArguments = tArguments; + } + } + return this.typeArguments = NO_TYPE_BINDINGS; + } + + /** + * @see org.eclipse.jdt.core.dom.IMethodBinding#isParameterizedMethod() + */ + public boolean isParameterizedMethod() { + return (this.binding instanceof ParameterizedGenericMethodBinding) + && !((ParameterizedGenericMethodBinding) this.binding).isRaw; + } + + /** + * @see org.eclipse.jdt.core.dom.IMethodBinding#isRawMethod() + */ + public boolean isRawMethod() { + return (this.binding instanceof ParameterizedGenericMethodBinding) + && ((ParameterizedGenericMethodBinding) this.binding).isRaw; + } + + public boolean isSubsignature(IMethodBinding otherMethod) { + try { + LookupEnvironment lookupEnvironment = this.resolver.lookupEnvironment(); + return lookupEnvironment != null + && lookupEnvironment.methodVerifier().isMethodSubsignature(this.binding, ((MethodBinding) otherMethod).binding); + } catch (AbortCompilation e) { + // don't surface internal exception to clients + // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=143013 + return false; + } + } + + /** + * @see org.eclipse.jdt.core.dom.IMethodBinding#getMethodDeclaration() + */ + public IMethodBinding getMethodDeclaration() { + return this.resolver.getMethodBinding(this.binding.original()); + } + + /** + * @see IMethodBinding#overrides(IMethodBinding) + */ + public boolean overrides(IMethodBinding otherMethod) { + LookupEnvironment lookupEnvironment = this.resolver.lookupEnvironment(); + return lookupEnvironment != null + && lookupEnvironment.methodVerifier().doesMethodOverride(this.binding, ((MethodBinding) otherMethod).binding); + } + + /** + * For debugging purpose only. + * @see java.lang.Object#toString() + */ + public String toString() { + return this.binding.toString(); + } +//{ObjectTeams: new query: + public boolean isCopied() { + return this.binding.copyInheritanceSrc != null; + } +// SH} +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodBindingOperator.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodBindingOperator.java new file mode 100644 index 000000000..152053869 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodBindingOperator.java @@ -0,0 +1,244 @@ +/********************************************************************** + * This file is part of "Object Teams Development Tooling"-Software + * + * Copyright 2009 Stephan Herrmann + * + * 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 + * $Id$ + * + * Please visit http://www.eclipse.org/objectteams for updates and contact. + * + * Contributors: + * Stephan Herrmann - Initial API and implementation + **********************************************************************/ +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * This class represents all information concerning HOW a method mapping connects + * its role/base features: + * <ul> + * <li>The binding kind as marked by one of the tokens <code>->,=>,<-</code> + * <li>An optional modifier, one of <code>before,replace,after</code> (callin) or <code>get,set</code> (callout-to-field). + * </ul> + * @author stephan + * @since 1.3.1 + */ +@SuppressWarnings("unchecked") +public class MethodBindingOperator extends ASTNode { + + public static final int KIND_CALLOUT = 1; + public static final int KIND_CALLOUT_OVERRIDE = 2; + public static final int KIND_CALLIN = 3; + + /** + * The "binding-kind" property of this node type. + */ + public static final SimplePropertyDescriptor BINDING_KIND_PROPERTY = + new SimplePropertyDescriptor(MethodBindingOperator.class, "bindingKind", int.class, MANDATORY); + + /** + * The "binding-modifier" structural property of this node type, none if regular callout. + */ + public static final ChildPropertyDescriptor BINDING_MODIFIER_PROPERTY = + new ChildPropertyDescriptor(MethodBindingOperator.class, "bindingModifier", Modifier.class, OPTIONAL, NO_CYCLE_RISK); //$NON-NLS-1$ + + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS_2_0; + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS_3_0; + + static + { + List propertyList = new ArrayList(1); + createPropertyList(MethodBindingOperator.class, propertyList); + addProperty(BINDING_KIND_PROPERTY, propertyList); + addProperty(BINDING_MODIFIER_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS_2_0 = reapPropertyList(propertyList); + + propertyList = new ArrayList(1); + createPropertyList(MethodBindingOperator.class, propertyList); + addProperty(BINDING_KIND_PROPERTY, propertyList); + addProperty(BINDING_MODIFIER_PROPERTY, propertyList); // one flag, not a bitset + PROPERTY_DESCRIPTORS_3_0 = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the AST.JLS* constants + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + */ + public static List propertyDescriptors(int apiLevel) + { + if(apiLevel == AST.JLS3) + return PROPERTY_DESCRIPTORS_3_0; + else + return PROPERTY_DESCRIPTORS_2_0; + } + + private int bindingKind = 0; // one of KIND_CALLIN, KIND_CALLOUT, KIND_CALLOUT_OVERRIDE; + /** + * The modifier flags; exactly one of before, after, replace. + * No default. + */ + private int bindingModifierFlag = 0; + private Modifier bindingModifier; + + public MethodBindingOperator(AST ast) { + super(ast); + } + + + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) + { + if (property == BINDING_MODIFIER_PROPERTY) + { + if (get) { + return bindingModifier(); + } else { + setBindingModifier((Modifier)child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + @Override + int internalGetSetIntProperty(SimplePropertyDescriptor property, boolean get, int value) { + if (property == BINDING_KIND_PROPERTY) { + if (get) { + return getBindingKind(); + } + else + { + setBindingKind(value); + return 0; + } + } + + // default impl to signal errors + return super.internalGetSetIntProperty(property, get, value); + } + + public int getBindingKind() { + return this.bindingKind; + } + + public void setBindingKind(int bindingKind) { + if (bindingKind < 0) { + throw new IllegalArgumentException(); + } + preValueChange(BINDING_KIND_PROPERTY); + this.bindingKind = bindingKind; + postValueChange(BINDING_KIND_PROPERTY); + } + + + /** + * Returns the callin modifiers explicitly specified on this declaration. + * + * @return exactly one of before, after, replace using constants from Modifier + * @see Modifier + */ + public int getBindingModifier() + { + if (this.bindingModifierFlag == 0 && this.bindingModifier != null) + { + this.bindingModifierFlag = this.bindingModifier.getKeyword().toFlagValue(); + } + return bindingModifierFlag; + } + + /** + * Sets the callin or c-t-f modifier explicitly specified on this declaration. + * + * @param modifiers the given modifiers (bit-wise or of <code>Modifier</code> constants) + * @see Modifier + */ + public void setBindingModifier(int modifiers) + { + setBindingModifier(this.ast.newModifier(Modifier.ModifierKeyword.fromFlagValue(modifiers))); + } + + public void setBindingModifier(Modifier modifier) { + ChildPropertyDescriptor propertyDescriptor = BINDING_MODIFIER_PROPERTY; + Modifier oldModifier = this.bindingModifier; + preReplaceChild(oldModifier, modifier, propertyDescriptor); + this.bindingModifierFlag = 0; // clear cached flags + this.bindingModifier = modifier; + postReplaceChild(oldModifier, modifier, propertyDescriptor); + } + + /** + * Returns the callin or c-t-f modifier for this mapping declaration. + * + * @see Modifier + * @return one of before, after, replace + */ + public Modifier bindingModifier() + { + return bindingModifier; + } + + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + acceptChild(visitor, this.bindingModifier); + } + visitor.endVisit(this); + } + + ASTNode clone0(AST target) { + MethodBindingOperator result = new MethodBindingOperator(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setBindingModifier(this.bindingModifier); + result.setBindingKind(this.bindingKind); + return result; + } + + int getNodeType0() { + return METHOD_BINDING_OPERATOR; + } + + List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + int memSize() { + // TODO Auto-generated method stub + return 0; + } + + boolean subtreeMatch0(ASTMatcher matcher, Object other) { + if (!(other instanceof MethodBindingOperator)) + return false; + MethodBindingOperator otherOp = (MethodBindingOperator) other; + return (otherOp.bindingKind == this.bindingKind) + && (otherOp.getBindingModifier() == this.getBindingModifier()); + } + + int treeSize() { + // TODO Auto-generated method stub + return 0; + } + +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodDeclaration.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodDeclaration.java new file mode 100644 index 000000000..16c219571 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodDeclaration.java @@ -0,0 +1,953 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + * Technical University Berlin - extended API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Method declaration AST node type. A method declaration + * is the union of a method declaration and a constructor declaration. + * For JLS2: + * <pre> + * MethodDeclaration: + * [ Javadoc ] { Modifier } ( Type | <b>void</b> ) Identifier <b>(</b> + * [ FormalParameter + * { <b>,</b> FormalParameter } ] <b>)</b> {<b>[</b> <b>]</b> } + * [ <b>throws</b> TypeName { <b>,</b> TypeName } ] ( Block | <b>;</b> ) + * ConstructorDeclaration: + * [ Javadoc ] { Modifier } Identifier <b>(</b> + * [ FormalParameter + * { <b>,</b> FormalParameter } ] <b>)</b> + * [<b>throws</b> TypeName { <b>,</b> TypeName } ] Block + * </pre> + * For JLS3, type parameters and reified modifiers + * (and annotations) were added: + * <pre> + * MethodDeclaration: + * [ Javadoc ] { ExtendedModifier } + * [ <b><</b> TypeParameter { <b>,</b> TypeParameter } <b>></b> ] + * ( Type | <b>void</b> ) Identifier <b>(</b> + * [ FormalParameter + * { <b>,</b> FormalParameter } ] <b>)</b> {<b>[</b> <b>]</b> } + * [ <b>throws</b> TypeName { <b>,</b> TypeName } ] ( Block | <b>;</b> ) + * ConstructorDeclaration: + * [ Javadoc ] { ExtendedModifier } + * [ <b><</b> TypeParameter { <b>,</b> TypeParameter } <b>></b> ] + * Identifier <b>(</b> + * [ FormalParameter + * { <b>,</b> FormalParameter } ] <b>)</b> + * [<b>throws</b> TypeName { <b>,</b> TypeName } ] Block + * </pre> + * <p> + * When a Javadoc comment is present, the source + * range begins with the first character of the "/**" comment delimiter. + * When there is no Javadoc comment, the source range begins with the first + * character of the first modifier keyword (if modifiers), or the + * first character of the "<" token (method, no modifiers, type parameters), + * or the first character of the return type (method, no modifiers, no type + * parameters), or the first character of the identifier (constructor, + * no modifiers). The source range extends through the last character of the + * ";" token (if no body), or the last character of the block (if body). + * </p> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class MethodDeclaration extends BodyDeclaration { + + /** + * The "javadoc" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor JAVADOC_PROPERTY = + internalJavadocPropertyFactory(MethodDeclaration.class); + + /** + * The "modifiers" structural property of this node type (JLS2 API only). + * @since 3.0 + */ + public static final SimplePropertyDescriptor MODIFIERS_PROPERTY = + internalModifiersPropertyFactory(MethodDeclaration.class); + + /** + * The "modifiers" structural property of this node type (added in JLS3 API). + * @since 3.1 + */ + public static final ChildListPropertyDescriptor MODIFIERS2_PROPERTY = + internalModifiers2PropertyFactory(MethodDeclaration.class); + + /** + * The "constructor" structural property of this node type. + * @since 3.0 + */ + public static final SimplePropertyDescriptor CONSTRUCTOR_PROPERTY = + new SimplePropertyDescriptor(MethodDeclaration.class, "constructor", boolean.class, MANDATORY); //$NON-NLS-1$ + + /** + * The "name" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor NAME_PROPERTY = + new ChildPropertyDescriptor(MethodDeclaration.class, "name", SimpleName.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "returnType" structural property of this node type (JLS2 API only). + * @since 3.0 + */ + public static final ChildPropertyDescriptor RETURN_TYPE_PROPERTY = + new ChildPropertyDescriptor(MethodDeclaration.class, "returnType", Type.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "returnType2" structural property of this node type (added in JLS3 API). + * @since 3.1 + */ + public static final ChildPropertyDescriptor RETURN_TYPE2_PROPERTY = + new ChildPropertyDescriptor(MethodDeclaration.class, "returnType2", Type.class, OPTIONAL, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "extraDimensions" structural property of this node type. + * @since 3.0 + */ + public static final SimplePropertyDescriptor EXTRA_DIMENSIONS_PROPERTY = + new SimplePropertyDescriptor(MethodDeclaration.class, "extraDimensions", int.class, MANDATORY); //$NON-NLS-1$ + + /** + * The "typeParameters" structural property of this node type (added in JLS3 API). + * @since 3.1 + */ + public static final ChildListPropertyDescriptor TYPE_PARAMETERS_PROPERTY = + new ChildListPropertyDescriptor(MethodDeclaration.class, "typeParameters", TypeParameter.class, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "parameters" structural property of this node type). + * @since 3.0 + */ + public static final ChildListPropertyDescriptor PARAMETERS_PROPERTY = + new ChildListPropertyDescriptor(MethodDeclaration.class, "parameters", SingleVariableDeclaration.class, CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "thrownExceptions" structural property of this node type). + * @since 3.0 + */ + public static final ChildListPropertyDescriptor THROWN_EXCEPTIONS_PROPERTY = + new ChildListPropertyDescriptor(MethodDeclaration.class, "thrownExceptions", Name.class, NO_CYCLE_RISK); //$NON-NLS-1$ + +//{ObjectTeams: new element: + /** + * The "guardPredicate" structural property of this node type. + * @since 0.9.25 + */ + public static final ChildPropertyDescriptor GUARD_PROPERTY = + new ChildPropertyDescriptor(MethodDeclaration.class, "guardPredicate", GuardPredicateDeclaration.class, OPTIONAL, NO_CYCLE_RISK); //$NON-NLS-1$ +// SH} + + /** + * The "body" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor BODY_PROPERTY = + new ChildPropertyDescriptor(MethodDeclaration.class, "body", Block.class, OPTIONAL, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + * @since 3.0 + */ + private static final List PROPERTY_DESCRIPTORS_2_0; + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + * @since 3.1 + */ + private static final List PROPERTY_DESCRIPTORS_3_0; + + static { + List propertyList = new ArrayList(10); + createPropertyList(MethodDeclaration.class, propertyList); + addProperty(JAVADOC_PROPERTY, propertyList); + addProperty(MODIFIERS_PROPERTY, propertyList); + addProperty(CONSTRUCTOR_PROPERTY, propertyList); + addProperty(RETURN_TYPE_PROPERTY, propertyList); + addProperty(NAME_PROPERTY, propertyList); + addProperty(PARAMETERS_PROPERTY, propertyList); + addProperty(EXTRA_DIMENSIONS_PROPERTY, propertyList); + addProperty(THROWN_EXCEPTIONS_PROPERTY, propertyList); +//{ObjectTeams: + addProperty(GUARD_PROPERTY, propertyList); +// SH} + addProperty(BODY_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS_2_0 = reapPropertyList(propertyList); + + propertyList = new ArrayList(12); + createPropertyList(MethodDeclaration.class, propertyList); + addProperty(JAVADOC_PROPERTY, propertyList); + addProperty(MODIFIERS2_PROPERTY, propertyList); + addProperty(CONSTRUCTOR_PROPERTY, propertyList); + addProperty(TYPE_PARAMETERS_PROPERTY, propertyList); + addProperty(RETURN_TYPE2_PROPERTY, propertyList); + addProperty(NAME_PROPERTY, propertyList); + addProperty(PARAMETERS_PROPERTY, propertyList); + addProperty(EXTRA_DIMENSIONS_PROPERTY, propertyList); + addProperty(THROWN_EXCEPTIONS_PROPERTY, propertyList); +//{ObjectTeams: + addProperty(GUARD_PROPERTY, propertyList); +// SH} + addProperty(BODY_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS_3_0 = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the AST.JLS* constants + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + if (apiLevel == AST.JLS2_INTERNAL) { + return PROPERTY_DESCRIPTORS_2_0; + } else { + return PROPERTY_DESCRIPTORS_3_0; + } + } + + /** + * <code>true</code> for a constructor, <code>false</code> for a method. + * Defaults to method. + */ + private boolean isConstructor = false; + + /** + * The method name; lazily initialized; defaults to an unspecified, + * legal Java identifier. + */ + private SimpleName methodName = null; + + /** + * The parameter declarations + * (element type: <code>SingleVariableDeclaration</code>). + * Defaults to an empty list. + */ + private ASTNode.NodeList parameters = + new ASTNode.NodeList(PARAMETERS_PROPERTY); + + /** + * The return type. + * JLS2 behevior: lazily initialized; defaults to void. + * JLS3 behavior; lazily initialized; defaults to void; null allowed. + * Note that this field is ignored for constructor declarations. + */ + private Type returnType = null; + + /** + * Indicated whether the return type has been initialized. + * @since 3.1 + */ + private boolean returnType2Initialized = false; + + /** + * The type paramters (element type: <code>TypeParameter</code>). + * Null in JLS2. Added in JLS3; defaults to an empty list + * (see constructor). + * @since 3.1 + */ + private ASTNode.NodeList typeParameters = null; + + /** + * The number of array dimensions that appear after the parameters, rather + * than after the return type itself; defaults to 0. + * + * @since 2.1 + */ + private int extraArrayDimensions = 0; + + /** + * The list of thrown exception names (element type: <code>Name</code>). + * Defaults to an empty list. + */ + private ASTNode.NodeList thrownExceptions = + new ASTNode.NodeList(THROWN_EXCEPTIONS_PROPERTY); + +//{ObjectTeams: new element: + GuardPredicateDeclaration _optionalGuardPredicate = null; +// SH} + /** + * The method body, or <code>null</code> if none. + * Defaults to none. + */ + private Block optionalBody = null; + + /** + * Creates a new AST node for a method declaration owned + * by the given AST. By default, the declaration is for a method of an + * unspecified, but legal, name; no modifiers; no javadoc; no type + * parameters; void return type; no parameters; no array dimensions after + * the parameters; no thrown exceptions; and no body (as opposed to an + * empty body). + * <p> + * N.B. This constructor is package-private; all subclasses must be + * declared in the same package; clients are unable to declare + * additional subclasses. + * </p> + * + * @param ast the AST that is to own this node + */ + MethodDeclaration(AST ast) { + super(ast); + if (ast.apiLevel >= AST.JLS3) { + this.typeParameters = new ASTNode.NodeList(TYPE_PARAMETERS_PROPERTY); + } + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + * @since 3.0 + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int internalGetSetIntProperty(SimplePropertyDescriptor property, boolean get, int value) { + if (property == MODIFIERS_PROPERTY) { + if (get) { + return getModifiers(); + } else { + internalSetModifiers(value); + return 0; + } + } + if (property == EXTRA_DIMENSIONS_PROPERTY) { + if (get) { + return getExtraDimensions(); + } else { + setExtraDimensions(value); + return 0; + } + } + // allow default implementation to flag the error + return super.internalGetSetIntProperty(property, get, value); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean internalGetSetBooleanProperty(SimplePropertyDescriptor property, boolean get, boolean value) { + if (property == CONSTRUCTOR_PROPERTY) { + if (get) { + return isConstructor(); + } else { + setConstructor(value); + return false; + } + } + // allow default implementation to flag the error + return super.internalGetSetBooleanProperty(property, get, value); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == JAVADOC_PROPERTY) { + if (get) { + return getJavadoc(); + } else { + setJavadoc((Javadoc) child); + return null; + } + } + if (property == NAME_PROPERTY) { + if (get) { + return getName(); + } else { + setName((SimpleName) child); + return null; + } + } + if (property == RETURN_TYPE_PROPERTY) { + if (get) { + return getReturnType(); + } else { + setReturnType((Type) child); + return null; + } + } + if (property == RETURN_TYPE2_PROPERTY) { + if (get) { + return getReturnType2(); + } else { + setReturnType2((Type) child); + return null; + } + } +//{ObjectTeams: + if (property == GUARD_PROPERTY) { + if (get) { + return getGuardPredicate(); + } else { + setGuardPredicate((GuardPredicateDeclaration) child); + return null; + } + } +// SH} + if (property == BODY_PROPERTY) { + if (get) { + return getBody(); + } else { + setBody((Block) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalGetChildListProperty(ChildListPropertyDescriptor property) { + if (property == MODIFIERS2_PROPERTY) { + return modifiers(); + } + if (property == TYPE_PARAMETERS_PROPERTY) { + return typeParameters(); + } + if (property == PARAMETERS_PROPERTY) { + return parameters(); + } + if (property == THROWN_EXCEPTIONS_PROPERTY) { + return thrownExceptions(); + } + // allow default implementation to flag the error + return super.internalGetChildListProperty(property); + } + + /* (omit javadoc for this method) + * Method declared on BodyDeclaration. + */ + final ChildPropertyDescriptor internalJavadocProperty() { + return JAVADOC_PROPERTY; + } + + /* (omit javadoc for this method) + * Method declared on BodyDeclaration. + */ + final ChildListPropertyDescriptor internalModifiers2Property() { + return MODIFIERS2_PROPERTY; + } + + /* (omit javadoc for this method) + * Method declared on BodyDeclaration. + */ + final SimplePropertyDescriptor internalModifiersProperty() { + return MODIFIERS_PROPERTY; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return METHOD_DECLARATION; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + MethodDeclaration result = new MethodDeclaration(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setJavadoc( + (Javadoc) ASTNode.copySubtree(target, getJavadoc())); + if (this.ast.apiLevel == AST.JLS2_INTERNAL) { + result.internalSetModifiers(getModifiers()); + result.setReturnType( + (Type) ASTNode.copySubtree(target, getReturnType())); + } + if (this.ast.apiLevel >= AST.JLS3) { + result.modifiers().addAll(ASTNode.copySubtrees(target, modifiers())); + result.typeParameters().addAll( + ASTNode.copySubtrees(target, typeParameters())); + result.setReturnType2( + (Type) ASTNode.copySubtree(target, getReturnType2())); + } + result.setConstructor(isConstructor()); + result.setExtraDimensions(getExtraDimensions()); + result.setName((SimpleName) getName().clone(target)); + result.parameters().addAll( + ASTNode.copySubtrees(target, parameters())); + result.thrownExceptions().addAll( + ASTNode.copySubtrees(target, thrownExceptions())); +//{ObjectTeams: + result.setGuardPredicate((GuardPredicateDeclaration)ASTNode.copySubtree(target, getGuardPredicate())); +// SH} + result.setBody( + (Block) ASTNode.copySubtree(target, getBody())); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + acceptChild(visitor, getJavadoc()); + if (this.ast.apiLevel == AST.JLS2_INTERNAL) { + acceptChild(visitor, getReturnType()); + } else { + acceptChildren(visitor, this.modifiers); + acceptChildren(visitor, this.typeParameters); + acceptChild(visitor, getReturnType2()); +//{ObjectTeams: + acceptChild(visitor, this.getGuardPredicate()); +// SH} + } + // n.b. visit return type even for constructors + acceptChild(visitor, getName()); + acceptChildren(visitor, this.parameters); + acceptChildren(visitor, this.thrownExceptions); + acceptChild(visitor, getBody()); + } + visitor.endVisit(this); + } + + /** + * Returns whether this declaration declares a constructor or a method. + * + * @return <code>true</code> if this is a constructor declaration, + * and <code>false</code> if this is a method declaration + */ + public boolean isConstructor() { + return this.isConstructor; + } + + /** + * Sets whether this declaration declares a constructor or a method. + * + * @param isConstructor <code>true</code> for a constructor declaration, + * and <code>false</code> for a method declaration + */ + public void setConstructor(boolean isConstructor) { + preValueChange(CONSTRUCTOR_PROPERTY); + this.isConstructor = isConstructor; + postValueChange(CONSTRUCTOR_PROPERTY); + } + + /** + * Returns the live ordered list of type parameters of this method + * declaration (added in JLS3 API). This list is non-empty for parameterized methods. + * + * @return the live list of type parameters + * (element type: <code>TypeParameter</code>) + * @exception UnsupportedOperationException if this operation is used in + * a JLS2 AST + * @since 3.1 + */ + public List typeParameters() { + // more efficient than just calling unsupportedIn2() to check + if (this.typeParameters == null) { + unsupportedIn2(); + } + return this.typeParameters; + } + + /** + * Returns the name of the method declared in this method declaration. + * For a constructor declaration, this should be the same as the name + * of the class. + * + * @return the method name node + */ + public SimpleName getName() { + if (this.methodName == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.methodName == null) { + preLazyInit(); + this.methodName = new SimpleName(this.ast); + postLazyInit(this.methodName, NAME_PROPERTY); + } + } + } + return this.methodName; + } + + /** + * Sets the name of the method declared in this method declaration to the + * given name. For a constructor declaration, this should be the same as + * the name of the class. + * + * @param methodName the new method name + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public void setName(SimpleName methodName) { + if (methodName == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.methodName; + preReplaceChild(oldChild, methodName, NAME_PROPERTY); + this.methodName = methodName; + postReplaceChild(oldChild, methodName, NAME_PROPERTY); + } + + /** + * Returns the live ordered list of method parameter declarations for this + * method declaration. + * + * @return the live list of method parameter declarations + * (element type: <code>SingleVariableDeclaration</code>) + */ + public List parameters() { + return this.parameters; + } + + /** + * Returns whether this method declaration declares a + * variable arity method (added in JLS3 API). The convenience method checks + * whether the last parameter is so marked. + * + * @return <code>true</code> if this is a variable arity method declaration, + * and <code>false</code> otherwise + * @exception UnsupportedOperationException if this operation is used in + * a JLS2 AST + * @see SingleVariableDeclaration#isVarargs() + * @since 3.1 + */ + public boolean isVarargs() { + // more efficient than just calling unsupportedIn2() to check + if (this.modifiers == null) { + unsupportedIn2(); + } + if (parameters().isEmpty()) { + return false; + } else { + SingleVariableDeclaration v = (SingleVariableDeclaration) parameters().get(parameters().size() - 1); + return v.isVarargs(); + } + } + + /** + * Returns the live ordered list of thrown exception names in this method + * declaration. + * + * @return the live list of exception names + * (element type: <code>Name</code>) + */ + public List thrownExceptions() { + return this.thrownExceptions; + } + + /** + * Returns the return type of the method declared in this method + * declaration, exclusive of any extra array dimensions (JLS2 API only). + * This is one of the few places where the void type is meaningful. + * <p> + * Note that this child is not relevant for constructor declarations + * (although, it does still figure in subtree equality comparisons + * and visits), and is devoid of the binding information ordinarily + * available. + * </p> + * + * @return the return type, possibly the void primitive type + * @exception UnsupportedOperationException if this operation is used in + * an AST later than JLS2 + * @deprecated In the JLS3 API, this method is replaced by {@link #getReturnType2()}, + * which may return <code>null</code>. + */ + public Type getReturnType() { + return internalGetReturnType(); + } + + /** + * Internal synonym for deprecated method. Used to avoid + * deprecation warnings. + * @since 3.1 + */ + /*package*/ final Type internalGetReturnType() { + supportedOnlyIn2(); + if (this.returnType == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.returnType == null) { + preLazyInit(); + this.returnType = this.ast.newPrimitiveType(PrimitiveType.VOID); + postLazyInit(this.returnType, RETURN_TYPE_PROPERTY); + } + } + } + return this.returnType; + } + + /** + * Sets the return type of the method declared in this method declaration + * to the given type, exclusive of any extra array dimensions (JLS2 API only). This is one + * of the few places where the void type is meaningful. + * <p> + * Note that this child is not relevant for constructor declarations + * (although it does still figure in subtree equality comparisons and visits). + * </p> + * + * @param type the new return type, possibly the void primitive type + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + * @exception UnsupportedOperationException if this operation is used in + * an AST later than JLS2 + * @deprecated In the JLS3 API, this method is replaced by + * {@link #setReturnType2(Type)}, which accepts <code>null</code>. + */ + public void setReturnType(Type type) { + internalSetReturnType(type); + } + + /** + * Internal synonym for deprecated method. Used to avoid + * deprecation warnings. + * @since 3.1 + */ + /*package*/ void internalSetReturnType(Type type) { + supportedOnlyIn2(); + if (type == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.returnType; + preReplaceChild(oldChild, type, RETURN_TYPE_PROPERTY); + this.returnType = type; + postReplaceChild(oldChild, type, RETURN_TYPE_PROPERTY); + } + + /** + * Returns the return type of the method declared in this method + * declaration, exclusive of any extra array dimensions (added in JLS3 API). + * This is one of the few places where the void type is meaningful. + * <p> + * Note that this child is not relevant for constructor declarations + * (although, if present, it does still figure in subtree equality comparisons + * and visits), and is devoid of the binding information ordinarily + * available. In the JLS2 API, the return type is mandatory. + * In the JLS3 API, the return type is optional. + * </p> + * + * @return the return type, possibly the void primitive type, + * or <code>null</code> if none + * @exception UnsupportedOperationException if this operation is used in + * a JLS2 AST + * @since 3.1 + */ + public Type getReturnType2() { + unsupportedIn2(); + if (this.returnType == null && !this.returnType2Initialized) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.returnType == null && !this.returnType2Initialized) { + preLazyInit(); + this.returnType = this.ast.newPrimitiveType(PrimitiveType.VOID); + this.returnType2Initialized = true; + postLazyInit(this.returnType, RETURN_TYPE2_PROPERTY); + } + } + } + return this.returnType; + } + + /** + * Sets the return type of the method declared in this method declaration + * to the given type, exclusive of any extra array dimensions (added in JLS3 API). + * This is one of the few places where the void type is meaningful. + * <p> + * Note that this child is not relevant for constructor declarations + * (although it does still figure in subtree equality comparisons and visits). + * In the JLS2 API, the return type is mandatory. + * In the JLS3 API, the return type is optional. + * </p> + * + * @param type the new return type, possibly the void primitive type, + * or <code>null</code> if none + * @exception UnsupportedOperationException if this operation is used in + * a JLS2 AST + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + * @since 3.1 + */ + public void setReturnType2(Type type) { + unsupportedIn2(); + this.returnType2Initialized = true; + ASTNode oldChild = this.returnType; + preReplaceChild(oldChild, type, RETURN_TYPE2_PROPERTY); + this.returnType = type; + postReplaceChild(oldChild, type, RETURN_TYPE2_PROPERTY); + } + + /** + * Returns the number of extra array dimensions over and above the + * explicitly-specified return type. + * <p> + * For example, <code>int foo()[][]</code> has a return type of + * <code>int</code> and two extra array dimensions; + * <code>int[][] foo()</code> has a return type of <code>int[][]</code> + * and zero extra array dimensions. The two constructs have different + * ASTs, even though there are really syntactic variants of the same + * method declaration. + * </p> + * + * @return the number of extra array dimensions + * @since 2.1 + */ + public int getExtraDimensions() { + return this.extraArrayDimensions; + } + + /** + * Sets the number of extra array dimensions over and above the + * explicitly-specified return type. + * <p> + * For example, <code>int foo()[][]</code> is rendered as a return + * type of <code>int</code> with two extra array dimensions; + * <code>int[][] foo()</code> is rendered as a return type of + * <code>int[][]</code> with zero extra array dimensions. The two + * constructs have different ASTs, even though there are really syntactic + * variants of the same method declaration. + * </p> + * + * @param dimensions the number of array dimensions + * @exception IllegalArgumentException if the number of dimensions is + * negative + * @since 2.1 + */ + public void setExtraDimensions(int dimensions) { + if (dimensions < 0) { + throw new IllegalArgumentException(); + } + preValueChange(EXTRA_DIMENSIONS_PROPERTY); + this.extraArrayDimensions = dimensions; + postValueChange(EXTRA_DIMENSIONS_PROPERTY); + } +//{ObjectTeams: accessors for new element + public void setGuardPredicate(GuardPredicateDeclaration predicate) { + ASTNode oldChild = this._optionalGuardPredicate; + preReplaceChild(oldChild, predicate, GUARD_PROPERTY); + this._optionalGuardPredicate = predicate; + postReplaceChild(oldChild, predicate, GUARD_PROPERTY); + } + + public GuardPredicateDeclaration getGuardPredicate() { + return _optionalGuardPredicate; + } +// SH} + /** + * Returns the body of this method declaration, or <code>null</code> if + * this method has <b>no</b> body. + * <p> + * Note that there is a subtle difference between having no body and having + * an empty body ("{}"). + * </p> + * + * @return the method body, or <code>null</code> if this method has no + * body + */ + public Block getBody() { + return this.optionalBody; + } + + /** + * Sets or clears the body of this method declaration. + * <p> + * Note that there is a subtle difference between having no body + * (as in <code>"void foo();"</code>) and having an empty body (as in + * "void foo() {}"). Abstract methods, and methods declared in interfaces, + * have no body. Non-abstract methods, and all constructors, have a body. + * </p> + * + * @param body the block node, or <code>null</code> if + * there is none + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setBody(Block body) { + // a MethodDeclaration may occur in a Block - must check cycles + ASTNode oldChild = this.optionalBody; + preReplaceChild(oldChild, body, BODY_PROPERTY); + this.optionalBody = body; + postReplaceChild(oldChild, body, BODY_PROPERTY); + } + + /** + * Resolves and returns the binding for the method or constructor declared + * in this method or constructor declaration. + * <p> + * Note that bindings are generally unavailable unless requested when the + * AST is being built. + * </p> + * + * @return the binding, or <code>null</code> if the binding cannot be + * resolved + */ + public IMethodBinding resolveBinding() { + return this.ast.getBindingResolver().resolveMethod(this); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return super.memSize() + 9 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.optionalDocComment == null ? 0 : getJavadoc().treeSize()) + + (this.modifiers == null ? 0 : this.modifiers.listSize()) + + (this.typeParameters == null ? 0 : this.typeParameters.listSize()) + + (this.methodName == null ? 0 : getName().treeSize()) + + (this.returnType == null ? 0 : this.returnType.treeSize()) + + this.parameters.listSize() + + this.thrownExceptions.listSize() + + (this.optionalBody == null ? 0 : getBody().treeSize()); + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodInvocation.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodInvocation.java new file mode 100644 index 000000000..c8e827325 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodInvocation.java @@ -0,0 +1,399 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Method invocation expression AST node type. + * For JLS2: + * <pre> + * MethodInvocation: + * [ Expression <b>.</b> ] Identifier + * <b>(</b> [ Expression { <b>,</b> Expression } ] <b>)</b> + * </pre> + * For JLS3, type arguments are added: + * <pre> + * MethodInvocation: + * [ Expression <b>.</b> ] + * [ <b><</b> Type { <b>,</b> Type } <b>></b> ] + * Identifier <b>(</b> [ Expression { <b>,</b> Expression } ] <b>)</b> + * </pre> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class MethodInvocation extends Expression { + + /** + * The "expression" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor EXPRESSION_PROPERTY = + new ChildPropertyDescriptor(MethodInvocation.class, "expression", Expression.class, OPTIONAL, CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "typeArguments" structural property of this node type (added in JLS3 API). + * @since 3.1 + */ + public static final ChildListPropertyDescriptor TYPE_ARGUMENTS_PROPERTY = + new ChildListPropertyDescriptor(MethodInvocation.class, "typeArguments", Type.class, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "name" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor NAME_PROPERTY = + new ChildPropertyDescriptor(MethodInvocation.class, "name", SimpleName.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "arguments" structural property of this node type. + * @since 3.0 + */ + public static final ChildListPropertyDescriptor ARGUMENTS_PROPERTY = + new ChildListPropertyDescriptor(MethodInvocation.class, "arguments", Expression.class, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + * @since 3.0 + */ + private static final List PROPERTY_DESCRIPTORS_2_0; + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + * @since 3.1 + */ + private static final List PROPERTY_DESCRIPTORS_3_0; + + static { + List properyList = new ArrayList(4); + createPropertyList(MethodInvocation.class, properyList); + addProperty(EXPRESSION_PROPERTY, properyList); + addProperty(NAME_PROPERTY, properyList); + addProperty(ARGUMENTS_PROPERTY, properyList); + PROPERTY_DESCRIPTORS_2_0 = reapPropertyList(properyList); + + properyList = new ArrayList(5); + createPropertyList(MethodInvocation.class, properyList); + addProperty(EXPRESSION_PROPERTY, properyList); + addProperty(TYPE_ARGUMENTS_PROPERTY, properyList); + addProperty(NAME_PROPERTY, properyList); + addProperty(ARGUMENTS_PROPERTY, properyList); + PROPERTY_DESCRIPTORS_3_0 = reapPropertyList(properyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + if (apiLevel == AST.JLS2_INTERNAL) { + return PROPERTY_DESCRIPTORS_2_0; + } else { + return PROPERTY_DESCRIPTORS_3_0; + } + } + + /** + * The expression; <code>null</code> for none; defaults to none. + */ + private Expression optionalExpression = null; + + /** + * The type arguments (element type: <code>Type</code>). + * Null in JLS2. Added in JLS3; defaults to an empty list + * (see constructor). + * @since 3.1 + */ + private ASTNode.NodeList typeArguments = null; + + /** + * The method name; lazily initialized; defaults to a unspecified, + * legal Java method name. + */ + private SimpleName methodName = null; + + /** + * The list of argument expressions (element type: + * <code>Expression</code>). Defaults to an empty list. + */ + private ASTNode.NodeList arguments = + new ASTNode.NodeList(ARGUMENTS_PROPERTY); + + /** + * Creates a new AST node for a method invocation expression owned by the + * given AST. By default, no expression, no type arguments, + * an unspecified, but legal, method name, and an empty list of arguments. + * + * @param ast the AST that is to own this node + */ + MethodInvocation(AST ast) { + super(ast); + if (ast.apiLevel >= AST.JLS3) { + this.typeArguments = new ASTNode.NodeList(TYPE_ARGUMENTS_PROPERTY); + } + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == NAME_PROPERTY) { + if (get) { + return getName(); + } else { + setName((SimpleName) child); + return null; + } + } + if (property == EXPRESSION_PROPERTY) { + if (get) { + return getExpression(); + } else { + setExpression((Expression) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalGetChildListProperty(ChildListPropertyDescriptor property) { + if (property == ARGUMENTS_PROPERTY) { + return arguments(); + } + if (property == TYPE_ARGUMENTS_PROPERTY) { + return typeArguments(); + } + // allow default implementation to flag the error + return super.internalGetChildListProperty(property); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return METHOD_INVOCATION; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + MethodInvocation result = new MethodInvocation(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setName((SimpleName) getName().clone(target)); + result.setExpression( + (Expression) ASTNode.copySubtree(target, getExpression())); + if (this.ast.apiLevel >= AST.JLS3) { + result.typeArguments().addAll(ASTNode.copySubtrees(target, typeArguments())); + } + result.arguments().addAll(ASTNode.copySubtrees(target, arguments())); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + acceptChild(visitor, getExpression()); + if (this.ast.apiLevel >= AST.JLS3) { + acceptChildren(visitor, this.typeArguments); + } + acceptChild(visitor, getName()); + acceptChildren(visitor, this.arguments); + } + visitor.endVisit(this); + } + + /** + * Returns the expression of this method invocation expression, or + * <code>null</code> if there is none. + * + * @return the expression node, or <code>null</code> if there is none + */ + public Expression getExpression() { + return this.optionalExpression; + } + + /** + * Returns <code>true</code> if the resolved return type has been inferred + * from the assignment context (JLS3 15.12.2.8), <code>false</code> otherwise. + * <p> + * This information is available only when bindings are requested when the AST is being built + * </p>. + * + * @return <code>true</code> if the resolved return type has been inferred + * from the assignment context (JLS3 15.12.2.8), <code>false</code> otherwise + * @since 3.3 + */ + public boolean isResolvedTypeInferredFromExpectedType() { + return this.ast.getBindingResolver().isResolvedTypeInferredFromExpectedType(this); + } + + /** + * Sets or clears the expression of this method invocation expression. + * + * @param expression the expression node, or <code>null</code> if + * there is none + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setExpression(Expression expression) { + ASTNode oldChild = this.optionalExpression; + preReplaceChild(oldChild, expression, EXPRESSION_PROPERTY); + this.optionalExpression = expression; + postReplaceChild(oldChild, expression, EXPRESSION_PROPERTY); + } + + /** + * Returns the live ordered list of type arguments of this method + * invocation (added in JLS3 API). + * + * @return the live list of type arguments + * (element type: <code>Type</code>) + * @exception UnsupportedOperationException if this operation is used in + * a JLS2 AST + * @since 3.1 + */ + public List typeArguments() { + // more efficient than just calling unsupportedIn2() to check + if (this.typeArguments == null) { + unsupportedIn2(); + } + return this.typeArguments; + } + + /** + * Returns the name of the method invoked in this expression. + * + * @return the method name node + */ + public SimpleName getName() { + if (this.methodName == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.methodName == null) { + preLazyInit(); + this.methodName = new SimpleName(this.ast); + postLazyInit(this.methodName, NAME_PROPERTY); + } + } + } + return this.methodName; + } + + /** + * Sets the name of the method invoked in this expression to the + * given name. + * + * @param name the new method name + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public void setName(SimpleName name) { + if (name == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.methodName; + preReplaceChild(oldChild, name, NAME_PROPERTY); + this.methodName = name; + postReplaceChild(oldChild, name, NAME_PROPERTY); + } + + /** + * Returns the live ordered list of argument expressions in this method + * invocation expression. + * + * @return the live list of argument expressions + * (element type: <code>Expression</code>) + */ + public List arguments() { + return this.arguments; + } + + /** + * Resolves and returns the binding for the method invoked by this + * expression. + * <p> + * Note that bindings are generally unavailable unless requested when the + * AST is being built. + * </p> + * + * @return the method binding, or <code>null</code> if the binding cannot + * be resolved + * @since 2.1 + */ + public IMethodBinding resolveMethodBinding() { + return this.ast.getBindingResolver().resolveMethod(this); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + // treat Code as free + return BASE_NODE_SIZE + 4 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.optionalExpression == null ? 0 : getExpression().treeSize()) + + (this.typeArguments == null ? 0 : this.typeArguments.listSize()) + + (this.methodName == null ? 0 : getName().treeSize()) + + (this.arguments == null ? 0 : this.arguments.listSize()); + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodMappingBinding.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodMappingBinding.java new file mode 100644 index 000000000..d67550442 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodMappingBinding.java @@ -0,0 +1,290 @@ +/********************************************************************** + * This file is part of "Object Teams Development Tooling"-Software + * + * Copyright 2005, 2007 Fraunhofer Gesellschaft, Munich, Germany, + * for its Fraunhofer Institute for Computer Architecture and Software + * Technology (FIRST), Berlin, Germany and Technical University Berlin, + * Germany. + * + * 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 + * $Id: MethodMappingBinding.java 23417 2010-02-03 20:13:55Z stephan $ + * + * Please visit http://www.eclipse.org/objectteams for updates and contact. + * + * Contributors: + * Fraunhofer FIRST - Initial API and implementation + * Technical University Berlin - Initial API and implementation + **********************************************************************/ +package org.eclipse.jdt.core.dom; + +import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; +import org.eclipse.jdt.internal.compiler.ast.Argument; +import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; +import org.eclipse.jdt.internal.compiler.parser.TerminalTokens; +import org.eclipse.objectteams.otdt.core.compiler.InferenceKind; + + +/** + * Internal implementation of callin/callout mapping bindings. + * + * @author mkr + */ +class MethodMappingBinding implements IMethodMappingBinding +{ + + private org.eclipse.objectteams.otdt.internal.core.compiler.lookup.CallinCalloutBinding _binding; + private BindingResolver _resolver; + private String _name; + private ITypeBinding _declaringClass; + private ITypeBinding _baseClass; + private IMethodBinding _roleMethod; + private IMethodBinding[] _baseMethods; + + MethodMappingBinding( + BindingResolver resolver, + org.eclipse.objectteams.otdt.internal.core.compiler.lookup.CallinCalloutBinding binding) + { + _resolver = resolver; + _binding = binding; + } + + // svenk: added to hold annotations for method getAnnotations() + private IAnnotationBinding[] annotations; + + /* + * @see IBinding#getName() + */ + public String getName() + { + if (_name == null) + { + _name = new String(_binding.readableName()); + } + + return _name; + } + + /* + * @see IMethodMappingBinding#getDeclaringRoleClass() + */ + public ITypeBinding getDeclaringRoleClass() + { + if (_declaringClass == null) + { + _declaringClass = _resolver.getTypeBinding(_binding._declaringRoleClass); + } + + return _declaringClass; + } + + /* + * @see IMethodMappingBinding#getReferencedBaseClass() + */ + public ITypeBinding getReferencedBaseClass() + { + if (_baseClass == null) + { + _baseClass = _resolver.getTypeBinding(_binding._declaringRoleClass.baseclass()); + //mkr: This is a workaround because _binding.referencedBaseClass is null + // _baseClass = _resolver.getTypeBinding(_binding._referencedBaseClass); + } + + return _baseClass; + } + + /* + * @see IMethodMappingBinding#getRoleMethod() + */ + public IMethodBinding getRoleMethod() + { + if (_roleMethod == null) + { + _roleMethod = _resolver.getMethodBinding(_binding._roleMethodBinding); + } + + return _roleMethod; + } + + /* + * @see IMethodMappingBinding#getBaseMethods() + */ + public IMethodBinding[] getBaseMethods() + { + if (_baseMethods == null) + { + MethodBinding[] methodBindings = this._binding._baseMethods; + if (methodBindings == null) + return new IMethodBinding[0]; + this._baseMethods = new IMethodBinding[methodBindings.length]; + for (int i = 0; i < methodBindings.length; i++) + this._baseMethods[i] = _resolver.getMethodBinding(methodBindings[i]); + } + + return _baseMethods; + } + + public String[] getBaseArgumentNames() { + MethodBinding[] methodBindings = this._binding._baseMethods; + if (methodBindings != null && methodBindings.length > 0) + { + String[] result = new String[methodBindings[0].parameters.length]; + AbstractMethodDeclaration methodDecl = methodBindings[0].sourceMethod(); + if (methodDecl != null) { + Argument[] args = methodDecl.arguments; + if (args != null) { + for (int i = 0; i < args.length; i++) + result[i] = String.valueOf(args[i].name); + + return result; + } + } + for (int i = 0; i < result.length; i++) + result[i] = "arg"+i; //$NON-NLS-1$ + return result; + } + return new String[0]; + } + + /* + * @see IBinding#getKind() + */ + public int getKind() + { + return IBinding.METHOD_MAPPING; + } + + /* + * @see IBinding#getModifiers() + */ + public int getModifiers() + { + if (_binding.type == org.eclipse.objectteams.otdt.internal.core.compiler.lookup.CallinCalloutBinding.CALLIN) + { + switch (_binding.callinModifier) + { + case TerminalTokens.TokenNamebefore: + return Modifier.OT_BEFORE_CALLIN; + case TerminalTokens.TokenNameafter: + return Modifier.OT_AFTER_CALLIN; + case TerminalTokens.TokenNamereplace: + return Modifier.OT_REPLACE_CALLIN; + default: + return 0; + } + } +// else if (_binding.type == org.eclipse.jdt.internal.compiler.lookup.CallinCalloutBinding.CALLOUT) +// { +// // As for now, CalloutMappings have no modifier, +// // since get and set are properties of FieldAccessSpec. +// } + + return 0; + } + + /* + * @see IBinding#isDeprecated() + */ + public boolean isDeprecated() + { + return false; + } + + /** + * @see IBinding#isSynthetic() + */ + public boolean isSynthetic() + { + return false; + } + + public boolean isCallin() { + return _binding.isCallin(); + } + + /* + * @see IBinding#getKey() + */ + public String getKey() + { + StringBuffer buffer = new StringBuffer(); + buffer.append(this.getDeclaringRoleClass().getKey()); + buffer.append('/'); + buffer.append(this.getName()); + buffer.append(')'); + + return buffer.toString(); + } + + /* + * For debugging purpose only. + * @see java.lang.Object#toString() + */ + public String toString() + { + return _binding.toString(); + } + + public IJavaElement getJavaElement() { + // SH: could not find a path that could possibly call this method [26.2.07] + return null; + } + + public boolean isEqualTo(IBinding other) { + if (this == other) + return true; + if (other == null) + return false; + + if (!(other instanceof MethodMappingBinding)) { + // consider a callout as equal to the role method it defines. + if (!this.isCallin() && this.getRoleMethod().isEqualTo(other)) + return true; + return false; + } + // untested below [06.02.09] + org.eclipse.objectteams.otdt.internal.core.compiler.lookup.CallinCalloutBinding otherBinding = ((MethodMappingBinding) other)._binding; + if (BindingComparator.isEqual(this._binding, otherBinding)) + return true; + return false; + } + +// (svenk: implement method from IBinding + public IAnnotationBinding[] getAnnotations() { + if (this.annotations != null) { + return this.annotations; + } + org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding[] annots = this._binding.getAnnotations(); + int length = annots == null ? 0 : annots.length; + if (annots == null) { + return this.annotations = AnnotationBinding.NoAnnotations; + } + IAnnotationBinding[] domInstances = new AnnotationBinding[length]; + for (int i = 0; i < length; i++) { + final IAnnotationBinding annotationInstance = this._resolver.getAnnotationInstance(annots[i]); + if (annotationInstance == null) { + return this.annotations = AnnotationBinding.NoAnnotations; + } + domInstances[i] = annotationInstance; + } + return this.annotations = domInstances; + } +// svenk) + + public boolean isRecovered() { + // method mappings are not (yet) recovered (cf. e.g., DefaultBindingResolver.getVariableBinding()) + return false; + } + + + + public InferenceKind getInferenceKind() { + if (this._binding != null) + return this._binding.inferred; + return InferenceKind.NONE; + } + +}
\ No newline at end of file diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodMappingElement.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodMappingElement.java new file mode 100644 index 000000000..fa1543bf7 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodMappingElement.java @@ -0,0 +1,162 @@ +/********************************************************************** + * This file is part of "Object Teams Development Tooling"-Software + * + * Copyright 2004, 2006 Fraunhofer Gesellschaft, Munich, Germany, + * for its Fraunhofer Institute for Computer Architecture and Software + * Technology (FIRST), Berlin, Germany and Technical University Berlin, + * Germany. + * + * 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 + * $Id: MethodMappingElement.java 23416 2010-02-03 19:59:31Z stephan $ + * + * Please visit http://www.eclipse.org/objectteams for updates and contact. + * + * Contributors: + * Fraunhofer FIRST - Initial API and implementation + * Technical University Berlin - Initial API and implementation + **********************************************************************/ + +package org.eclipse.jdt.core.dom; + +/** + * NEW for OTDT + * + * Abstract base class of all AST nodes that represent elements for + * method mapping like + * "void setValue(Integer i) -> set int val" . + * + * MethodSpec, e.g. "void setValue(Integer i)" + * FieldAccessSpec, e.g. "set int val" + * + * @author jsv + * @version $Id: MethodMappingElement.java 23416 2010-02-03 19:59:31Z stephan $ + */ +public abstract class MethodMappingElement extends ASTNode { + + /** + * Creates a new AST node for an expression owned by the given AST. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + MethodMappingElement(AST ast) { + super(ast); + } + + /** + * The signature flag. + * True if MethodMappingElement have a signature + */ + private boolean _hasSignature = false; + + /** + * The element name; lazily initialized; defaults to an unspecified, + * legal Java identifier. + */ + private SimpleName _name = null; + + /** + * Returns structural property descriptor for the "signature" property + * of this node. + * + * @return the property descriptor + */ + abstract SimplePropertyDescriptor internalSignatureProperty(); + + /** + * Returns structural property descriptor for the "name" property + * of this node. + * + * @return the property descriptor + */ + abstract ChildPropertyDescriptor internalNameProperty(); + + /** + * Creates and returns a structural property descriptor for the + * "signature" property declared on the given concrete node type. + * + * @return the property descriptor + */ + static final SimplePropertyDescriptor internalSignaturePropertyFactory(Class nodeClass) { + return new SimplePropertyDescriptor(nodeClass, "signature", boolean.class, MANDATORY); //$NON-NLS-1$ + } + + /** + * Creates and returns a structural property descriptor for the + * "name" property declared on the given concrete node type. + * + * @return the property descriptor + */ + static final ChildPropertyDescriptor internalNamePropertyFactory(Class nodeClass) { + return new ChildPropertyDescriptor(nodeClass, "name", SimpleName.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$ + } + + /** + * Returns the signature flag + */ + public boolean hasSignature() + { + return _hasSignature; + } + + /** + * Sets the signature flag. + */ + public void setSignatureFlag(boolean hasSignature) + { + SimplePropertyDescriptor p = internalSignatureProperty(); + preValueChange(p); + this._hasSignature = hasSignature; + postValueChange(p); + } + + /** + * Returns the name of the MethodMappingElement + * + * @return the method name node + */ + public SimpleName getName() + { + if (this._name == null) + { + // lazy init must be thread-safe for readers + synchronized (this) + { + if (this._name == null) + { + preLazyInit(); + this._name = new SimpleName(this.ast); + postLazyInit(this._name, internalNameProperty()); + } + } + } + return this._name; + } + + /** + * Sets the name of the MethodMappingElement + * + * @param newName the new element name + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public void setName(SimpleName newName) + { + if (newName == null) + { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this._name; + preReplaceChild(oldChild, newName, internalNameProperty()); + this._name = newName; + postReplaceChild(oldChild, newName, internalNameProperty()); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodRef.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodRef.java new file mode 100644 index 000000000..c174784ec --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodRef.java @@ -0,0 +1,317 @@ +/******************************************************************************* + * Copyright (c) 2004, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * AST node for a method or constructor reference within a doc comment + * ({@link Javadoc}). The principal uses of these are in "@see" and "@link" + * tag elements, for references to method and constructor members. + * <pre> + * MethodRef: + * [ Name ] <b>#</b> Identifier + * <b>(</b> [ MethodRefParameter | { <b>,</b> MethodRefParameter } ] <b>)</b> + * </pre> + * + * @see Javadoc + * @since 3.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class MethodRef extends ASTNode implements IDocElement { + + /** + * The "qualifier" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor QUALIFIER_PROPERTY = + new ChildPropertyDescriptor(MethodRef.class, "qualifier", Name.class, OPTIONAL, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "name" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor NAME_PROPERTY = + new ChildPropertyDescriptor(MethodRef.class, "name", SimpleName.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "parameters" structural property of this node type. + * @since 3.0 + */ + public static final ChildListPropertyDescriptor PARAMETERS_PROPERTY = + new ChildListPropertyDescriptor(MethodRef.class, "parameters", MethodRefParameter.class, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List properyList = new ArrayList(4); + createPropertyList(MethodRef.class, properyList); + addProperty(QUALIFIER_PROPERTY, properyList); + addProperty(NAME_PROPERTY, properyList); + addProperty(PARAMETERS_PROPERTY, properyList); + PROPERTY_DESCRIPTORS = reapPropertyList(properyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the AST.JLS* constants + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The optional qualifier; <code>null</code> for none; defaults to none. + */ + private Name optionalQualifier = null; + + /** + * The method name; lazily initialized; defaults to a unspecified, + * legal Java method name. + */ + private SimpleName methodName = null; + + /** + * The parameter declarations + * (element type: <code>MethodRefParameter</code>). + * Defaults to an empty list. + */ + private ASTNode.NodeList parameters = + new ASTNode.NodeList(PARAMETERS_PROPERTY); + + + /** + * Creates a new AST node for a method reference owned by the given + * AST. By default, the method reference is for a method with an + * unspecified, but legal, name; no qualifier; and an empty parameter + * list. + * <p> + * N.B. This constructor is package-private; all subclasses must be + * declared in the same package; clients are unable to declare + * additional subclasses. + * </p> + * + * @param ast the AST that is to own this node + */ + MethodRef(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == QUALIFIER_PROPERTY) { + if (get) { + return getQualifier(); + } else { + setQualifier((Name) child); + return null; + } + } + if (property == NAME_PROPERTY) { + if (get) { + return getName(); + } else { + setName((SimpleName) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalGetChildListProperty(ChildListPropertyDescriptor property) { + if (property == PARAMETERS_PROPERTY) { + return parameters(); + } + // allow default implementation to flag the error + return super.internalGetChildListProperty(property); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return METHOD_REF; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + MethodRef result = new MethodRef(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setQualifier((Name) ASTNode.copySubtree(target, getQualifier())); + result.setName((SimpleName) ASTNode.copySubtree(target, getName())); + result.parameters().addAll( + ASTNode.copySubtrees(target, parameters())); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + acceptChild(visitor, getQualifier()); + acceptChild(visitor, getName()); + acceptChildren(visitor, this.parameters); + } + visitor.endVisit(this); + } + + /** + * Returns the qualifier of this method reference, or + * <code>null</code> if there is none. + * + * @return the qualifier name node, or <code>null</code> if there is none + */ + public Name getQualifier() { + return this.optionalQualifier; + } + + /** + * Sets or clears the qualifier of this method reference. + * + * @param name the qualifier name node, or <code>null</code> if + * there is none + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public void setQualifier(Name name) { + ASTNode oldChild = this.optionalQualifier; + preReplaceChild(oldChild, name, QUALIFIER_PROPERTY); + this.optionalQualifier = name; + postReplaceChild(oldChild, name, QUALIFIER_PROPERTY); + } + + /** + * Returns the name of the referenced method or constructor. + * + * @return the method or constructor name node + */ + public SimpleName getName() { + if (this.methodName == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.methodName == null) { + preLazyInit(); + this.methodName = new SimpleName(this.ast); + postLazyInit(this.methodName, NAME_PROPERTY); + } + } + } + return this.methodName; + } + + /** + * Sets the name of the referenced method or constructor to the + * given name. + * + * @param name the new method or constructor name node + * @exception IllegalArgumentException if: + * <ul> + * <li>the name is <code>null</code></li> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public void setName(SimpleName name) { + if (name == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.methodName; + preReplaceChild(oldChild, name, NAME_PROPERTY); + this.methodName = name; + postReplaceChild(oldChild, name, NAME_PROPERTY); + } + + /** + * Returns the live ordered list of method parameter references for this + * method reference. + * + * @return the live list of method parameter references + * (element type: <code>MethodRefParameter</code>) + */ + public List parameters() { + return this.parameters; + } + + /** + * Resolves and returns the binding for the entity referred to by + * this method reference. + * <p> + * Note that bindings are generally unavailable unless requested when the + * AST is being built. + * </p> + * + * @return the binding, or <code>null</code> if the binding cannot be + * resolved + */ + public final IBinding resolveBinding() { + return this.ast.getBindingResolver().resolveReference(this); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return BASE_NODE_SIZE + 3 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.optionalQualifier == null ? 0 : getQualifier().treeSize()) + + (this.methodName == null ? 0 : getName().treeSize()) + + this.parameters.listSize(); + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodRefParameter.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodRefParameter.java new file mode 100644 index 000000000..3e8c2ee09 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodRefParameter.java @@ -0,0 +1,358 @@ +/******************************************************************************* + * Copyright (c) 2004, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * AST node for a parameter within a method reference ({@link MethodRef}). + * These nodes only occur within doc comments ({@link Javadoc}). + * For JLS2: + * <pre> + * MethodRefParameter: + * Type [ Identifier ] + * </pre> + * For JLS3, the variable arity indicator was added: + * <pre> + * MethodRefParameter: + * Type [ <b>...</b> ] [ Identifier ] + * </pre> + * <p> + * Note: The 1.5 spec for the Javadoc tool does not mention the possibility + * of a variable arity indicator in method references. However, the 1.5 + * Javadoc tool itself does indeed support it. Since it makes sense to have + * a way to explicitly refer to variable arity methods, it seems more likely + * that the Javadoc spec is wrong in this case. + * </p> + * + * @see Javadoc + * @since 3.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class MethodRefParameter extends ASTNode { + + /** + * The "type" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor TYPE_PROPERTY = + new ChildPropertyDescriptor(MethodRefParameter.class, "type", Type.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "varargs" structural property of this node type (added in JLS3 API). + * @since 3.1 + */ + public static final SimplePropertyDescriptor VARARGS_PROPERTY = + new SimplePropertyDescriptor(MethodRefParameter.class, "varargs", boolean.class, MANDATORY); //$NON-NLS-1$ + + /** + * The "name" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor NAME_PROPERTY = + new ChildPropertyDescriptor(MethodRefParameter.class, "name", SimpleName.class, OPTIONAL, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + * @since 3.0 + */ + private static final List PROPERTY_DESCRIPTORS_2_0; + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + * @since 3.1 + */ + private static final List PROPERTY_DESCRIPTORS_3_0; + + static { + List properyList = new ArrayList(3); + createPropertyList(MethodRefParameter.class, properyList); + addProperty(TYPE_PROPERTY, properyList); + addProperty(NAME_PROPERTY, properyList); + PROPERTY_DESCRIPTORS_2_0 = reapPropertyList(properyList); + + properyList = new ArrayList(3); + createPropertyList(MethodRefParameter.class, properyList); + addProperty(TYPE_PROPERTY, properyList); + addProperty(VARARGS_PROPERTY, properyList); + addProperty(NAME_PROPERTY, properyList); + PROPERTY_DESCRIPTORS_3_0 = reapPropertyList(properyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the AST.JLS* constants + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + if (apiLevel == AST.JLS2_INTERNAL) { + return PROPERTY_DESCRIPTORS_2_0; + } else { + return PROPERTY_DESCRIPTORS_3_0; + } + } + + /** + * The type; lazily initialized; defaults to a unspecified, + * legal type. + */ + private Type type = null; + + /** + * Indicates the last parameter of a variable arity method; + * defaults to false. + * + * @since 3.1 + */ + private boolean variableArity = false; + + /** + * The parameter name, or <code>null</code> if none; none by + * default. + */ + private SimpleName optionalParameterName = null; + + /** + * Creates a new AST node for a method referenece parameter owned by the given + * AST. By default, the node has an unspecified (but legal) type, + * not variable arity, and no parameter name. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + MethodRefParameter(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == TYPE_PROPERTY) { + if (get) { + return getType(); + } else { + setType((Type) child); + return null; + } + } + if (property == NAME_PROPERTY) { + if (get) { + return getName(); + } else { + setName((SimpleName) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean internalGetSetBooleanProperty(SimplePropertyDescriptor property, boolean get, boolean value) { + if (property == VARARGS_PROPERTY) { + if (get) { + return isVarargs(); + } else { + setVarargs(value); + return false; + } + } + // allow default implementation to flag the error + return super.internalGetSetBooleanProperty(property, get, value); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return METHOD_REF_PARAMETER; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + MethodRefParameter result = new MethodRefParameter(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setType((Type) ASTNode.copySubtree(target, getType())); + if (this.ast.apiLevel >= AST.JLS3) { + result.setVarargs(isVarargs()); + } + result.setName((SimpleName) ASTNode.copySubtree(target, getName())); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + acceptChild(visitor, getType()); + acceptChild(visitor, getName()); + } + visitor.endVisit(this); + } + + /** + * Returns the paramter type. + * + * @return the parameter type + */ + public Type getType() { + if (this.type == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.type == null) { + preLazyInit(); + this.type = this.ast.newPrimitiveType(PrimitiveType.INT); + postLazyInit(this.type, TYPE_PROPERTY); + } + } + } + return this.type; + } + + /** + * Sets the paramter type to the given type. + * + * @param type the new type + * @exception IllegalArgumentException if: + * <ul> + * <li>the type is <code>null</code></li> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public void setType(Type type) { + if (type == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.type; + preReplaceChild(oldChild, type, TYPE_PROPERTY); + this.type = type; + postReplaceChild(oldChild, type, TYPE_PROPERTY); + } + + /** + * Returns whether this method reference parameter is for + * the last parameter of a variable arity method (added in JLS3 API). + * <p> + * Note that the binding for the type <code>Foo</code>in the vararg method + * reference <code>#fun(Foo...)</code> is always for the type as + * written; i.e., the type binding for <code>Foo</code>. However, if you + * navigate from the MethodRef to its method binding to the + * type binding for its last parameter, the type binding for the vararg + * parameter is always an array type (i.e., <code>Foo[]</code>) reflecting + * the way vararg methods get compiled. + * </p> + * + * @return <code>true</code> if this is a variable arity parameter, + * and <code>false</code> otherwise + * @exception UnsupportedOperationException if this operation is used in + * a JLS2 AST + * @since 3.1 + */ + public boolean isVarargs() { + unsupportedIn2(); + return this.variableArity; + } + + /** + * Sets whether this method reference parameter is for the last parameter of + * a variable arity method (added in JLS3 API). + * + * @param variableArity <code>true</code> if this is a variable arity + * parameter, and <code>false</code> otherwise + * @since 3.1 + */ + public void setVarargs(boolean variableArity) { + unsupportedIn2(); + preValueChange(VARARGS_PROPERTY); + this.variableArity = variableArity; + postValueChange(VARARGS_PROPERTY); + } + + /** + * Returns the parameter name, or <code>null</code> if there is none. + * + * @return the parameter name node, or <code>null</code> if there is none + */ + public SimpleName getName() { + return this.optionalParameterName; + } + + /** + * Sets or clears the parameter name. + * + * @param name the parameter name node, or <code>null</code> if + * there is none + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public void setName(SimpleName name) { + ASTNode oldChild = this.optionalParameterName; + preReplaceChild(oldChild, name, NAME_PROPERTY); + this.optionalParameterName = name; + postReplaceChild(oldChild, name, NAME_PROPERTY); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return BASE_NODE_SIZE + 2 * 5; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.type == null ? 0 : getType().treeSize()) + + (this.optionalParameterName == null ? 0 : getName().treeSize()); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodSpec.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodSpec.java new file mode 100644 index 000000000..00131893c --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodSpec.java @@ -0,0 +1,557 @@ +/******************************************************************************* + * Copyright (c) 2000, 2010 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 + * $Id$ + * + * Please visit http://www.eclipse.org/objectteams for updates and contact. + * + * Contributors: + * IBM Corporation - initial API and implementation + * Fraunhofer FIRST - extended API and implementation + * Technical University Berlin - extended API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * NEW for OTDT, built in analogy to MethodDeclaration. + * + * Represents DOM-ASTNode for callout binding to a method of the corresponding + * base class, which has to handle code + * from e.g. : + * baseMethod + * to e.g. : + * String roleGetString(int b, String str) + * + * This class has following properties: + * parameters, + * returnType, + * name, + * signature + * + * This AST node has no modifier. + * + * This node can be used in CalloutMethodDeclaration and + * CallinMappingDeclaration + * + * @author jsv + */ +public class MethodSpec extends MethodMappingElement +{ + /** + * The "signature" structural property of this node type. + */ + public static final SimplePropertyDescriptor SIGNATURE_PROPERTY = + internalSignaturePropertyFactory(MethodSpec.class); + + /** + * The "covariantReturnType" property, flagging if "+" has been specified in the source. + * @since OTDT 1.1.3 + */ + public static final SimplePropertyDescriptor COVARIANT_RETURN_PROPERTY = + new SimplePropertyDescriptor(MethodSpec.class, "covariantReturn", boolean.class, MANDATORY); //$NON-NLS-1$ + + /** + * The "name" structural property of this node type. + */ + public static final ChildPropertyDescriptor NAME_PROPERTY = + internalNamePropertyFactory(MethodSpec.class); + + /** + * The "returnType" structural property of this node type (JLS2 API only). + */ + // TODO (jeem) When JLS3 support is complete (post 3.0) - deprecated Replaced by {@link #RETURN_TYPE2_PROPERTY} in the JLS3 API. + public static final ChildPropertyDescriptor RETURN_TYPE_PROPERTY = + new ChildPropertyDescriptor(MethodSpec.class, "returnType", Type.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "returnType2" structural property of this node type (added in JLS3 API). + * @since 3.1 + */ + public static final ChildPropertyDescriptor RETURN_TYPE2_PROPERTY = + new ChildPropertyDescriptor(MethodSpec.class, "returnType2", Type.class, OPTIONAL, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "typeParameters" structural property of this node type (added in JLS3 API). + * @since OTDT 1.1.3 + */ + public static final ChildListPropertyDescriptor TYPE_PARAMETERS_PROPERTY = + new ChildListPropertyDescriptor(MethodSpec.class, "typeParameters", TypeParameter.class, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "parameters" structural property of this node type). + */ + public static final ChildListPropertyDescriptor PARAMETERS_PROPERTY = + new ChildListPropertyDescriptor(MethodSpec.class, "parameters", SingleVariableDeclaration.class, CYCLE_RISK); //$NON-NLS-1$ + + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS_2_0; + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + * @since 3.1 + */ + private static final List PROPERTY_DESCRIPTORS_3_0; + + + static + { + List propertyList = new ArrayList(6); + createPropertyList(MethodSpec.class, propertyList); + addProperty(RETURN_TYPE_PROPERTY, propertyList); + addProperty(NAME_PROPERTY, propertyList); + addProperty(PARAMETERS_PROPERTY, propertyList); + addProperty(SIGNATURE_PROPERTY, propertyList); + addProperty(COVARIANT_RETURN_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS_2_0 = reapPropertyList(propertyList); + + propertyList = new ArrayList(7); + createPropertyList(MethodSpec.class, propertyList); + addProperty(RETURN_TYPE2_PROPERTY, propertyList); + addProperty(TYPE_PARAMETERS_PROPERTY, propertyList); + addProperty(NAME_PROPERTY, propertyList); + addProperty(PARAMETERS_PROPERTY, propertyList); + addProperty(SIGNATURE_PROPERTY, propertyList); + addProperty(COVARIANT_RETURN_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS_3_0 = reapPropertyList(propertyList); + + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the AST.JLS* constants + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + if (apiLevel == AST.JLS2_INTERNAL) { + return PROPERTY_DESCRIPTORS_2_0; + } else { + return PROPERTY_DESCRIPTORS_3_0; + } + } + + /** + * The parameter declarations + * (element type: <code>SingleVariableDeclaration</code>). + * Defaults to an empty list. + */ + private ASTNode.NodeList parameters = + new ASTNode.NodeList(PARAMETERS_PROPERTY); + + /** + * The return type. + * JLS2 behevior: lazily initialized; defaults to void. + * Note that this field is ignored for constructor declarations. + */ + private Type returnType = null; + + /** + * Indicated whether the return type has been initialized. + * @since 3.1 + */ + private boolean returnType2Initialized = false; + + /** + * The type paramters (element type: <code>TypeParameter</code>). + * (see constructor). + * @since OTDT 1.1.3 + */ + private ASTNode.NodeList typeParameters = null; + + /** + * Whether the return type was specified with "+" to match covariant return types, too. + * @since OTDT 1.1.3 + */ + private boolean _hasCovariantReturn; + + /** + * Creates a new AST node for a method spec declaration owned + * by the given AST. By default, the declaration is for a method spec + * of an unspecified, but legal, name; no modifiers; no javadoc; no type + * parameters; void return type; no parameters; no array dimensions after + * the parameters; no thrown exceptions; and no body (as opposed to an + * empty body). + * <p> + * N.B. This constructor is package-private; all subclasses must be + * declared in the same package; clients are unable to declare + * additional subclasses. + * </p> + * + * @param ast the AST that is to own this node + */ + MethodSpec(AST ast) + { + super(ast); + if (ast.apiLevel >= AST.JLS3) + this.typeParameters = new ASTNode.NodeList(TYPE_PARAMETERS_PROPERTY); + } + + /** + * Returns the covariantReturn flag + * @since OTDT 1.1.3 + */ + public boolean hasCovariantReturn() { + return _hasCovariantReturn; + } + + /** + * Sets the covariantReturn flag. + * @since OTDT 1.1.3 + */ + public void setCovariantReturnFlag(boolean hasCovariantReturn) + { + preValueChange(COVARIANT_RETURN_PROPERTY); + this._hasCovariantReturn = hasCovariantReturn; + postValueChange(COVARIANT_RETURN_PROPERTY); + } + + final List internalStructuralPropertiesForType(int apiLevel) + { + return propertyDescriptors(apiLevel); + } + + final boolean internalGetSetBooleanProperty(SimplePropertyDescriptor property, boolean get, boolean value) + { + if (property == SIGNATURE_PROPERTY) + { + if (get) { + return hasSignature(); + } else { + setSignatureFlag(value); + return false; + } + } + if (property == COVARIANT_RETURN_PROPERTY) + { + if (get) { + return hasCovariantReturn(); + } else { + setCovariantReturnFlag(value); + return false; + } + } + + return super.internalGetSetBooleanProperty(property, get, value); + } + + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) + { + if (property == NAME_PROPERTY) + { + if (get) + { + return getName(); + } + else + { + setName((SimpleName) child); + return null; + } + } + if (property == RETURN_TYPE_PROPERTY) + { + if (get) + { + return getReturnType(); + } + else + { + setReturnType((Type) child); + return null; + } + } + if(property == RETURN_TYPE2_PROPERTY) { + if(get) + return getReturnType2(); + else { + setReturnType2((Type) child); + return null; + } + } + + + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + final List internalGetChildListProperty(ChildListPropertyDescriptor property) + { + if (property == TYPE_PARAMETERS_PROPERTY) { + return typeParameters(); + } + if (property == PARAMETERS_PROPERTY) { + return parameters(); + } + // allow default implementation to flag the error + return super.internalGetChildListProperty(property); + } + + + final ChildListPropertyDescriptor internalModifiers2Property() + { + return null; + } + + SimplePropertyDescriptor internalSignatureProperty() { + return SIGNATURE_PROPERTY; + } + + ChildPropertyDescriptor internalNameProperty() { + return NAME_PROPERTY; + } + + final int getNodeType0() + { + return METHOD_SPEC; + } + + @SuppressWarnings("unchecked") + ASTNode clone0(AST target) + { + MethodSpec result = new MethodSpec(target); + result.setSourceRange(this.getStartPosition(), this.getLength()); + if (this.ast.apiLevel == AST.JLS2) + { + result.setReturnType( + (Type) ASTNode.copySubtree(target, getReturnType())); + } + if (this.ast.apiLevel >= AST.JLS3) + { + result.setReturnType2( + (Type) ASTNode.copySubtree(target, getReturnType2())); + result.typeParameters().addAll( + ASTNode.copySubtrees(target, typeParameters())); + } + result.setName((SimpleName) getName().clone(target)); + result.parameters().addAll( + ASTNode.copySubtrees(target, parameters())); + result.setSignatureFlag(this.hasSignature()); + result.setCovariantReturnFlag(this.hasCovariantReturn()); + return result; + } + + final boolean subtreeMatch0(ASTMatcher matcher, Object other) + { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + void accept0(ASTVisitor visitor) + { + boolean visitChildren = visitor.visit(this); + if (visitChildren) + { + // visit children in normal left to right reading order + if (this.ast.apiLevel == AST.JLS2) + { + acceptChild(visitor, getReturnType()); + } + else + { +// acceptChildren(visitor, this.modifiers); + acceptChild(visitor, getReturnType2()); + } + acceptChild(visitor, getName()); + acceptChildren(visitor, this.typeParameters); + acceptChildren(visitor, this.parameters); + } + visitor.endVisit(this); + } + + /** + * Returns the live ordered list of method parameter declarations for this + * method spec. + * + * @return the live list of method parameter declarations + * (element type: <code>SingleVariableDeclaration</code>) + */ + public List parameters() { + return this.parameters; + } + + /** + * Returns the live ordered list of type parameters of this method + * declaration (added in JLS3 API). This list is non-empty for parameterized methods. + * + * @return the live list of type parameters + * (element type: <code>TypeParameter</code>) + * @exception UnsupportedOperationException if this operation is used in + * a JLS2 AST + * @since OTDT 1.1.3 + */ + public List typeParameters() { + // more efficient than just calling unsupportedIn2() to check + if (this.typeParameters == null) { + unsupportedIn2(); + } + return this.typeParameters; + } + + public IMethodBinding resolveBinding() { + return this.ast.getBindingResolver().resolveMethod(this); + } + + /** + * Returns the return type of the method declared in this method spec, + * exclusive of any extra array dimensions (JLS2 API only). + * This is one of the few places where the void type is meaningful. + * <p> + * Note that this child is not relevant for constructor declarations + * (although, it does still figure in subtree equality comparisons + * and visits), and is devoid of the binding information ordinarily + * available. + * </p> + * + * @return the return type, possibly the void primitive type + * @exception UnsupportedOperationException if this operation is used in + * an AST later than JLS2 + */ + // TODO (jeem) When JLS3 support is complete (post 3.0) - deprecated In the JLS3 API, this method is replaced by <code>getReturnType2</code>, which may return <code>null</code>. + public Type getReturnType() + { + supportedOnlyIn2(); + if (this.returnType == null) + { + // lazy init must be thread-safe for readers + synchronized (this) + { + if (this.returnType == null) + { + preLazyInit(); + this.returnType = this.ast.newPrimitiveType(PrimitiveType.VOID); + postLazyInit(this.returnType, RETURN_TYPE_PROPERTY); + } + } + } + return this.returnType; + } + + /** + * Sets the return type of the method declared in this method spec + * declaration to the given type, exclusive of any extra array dimensions + * (JLS2 API only). This is one of the few places where the void type is meaningful. + * <p> + * Note that this child is not relevant for constructor declarations + * (although it does still figure in subtree equality comparisons and visits). + * </p> + * + * @param type the new return type, possibly the void primitive type + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + * @exception UnsupportedOperationException if this operation is used in + * an AST later than JLS2 + */ + // TODO (jeem) When JLS3 support is complete (post 3.0) - deprecated In the JLS3 API, this method is replaced by <code>setReturnType2</code>, which accepts <code>null</code>. + public void setReturnType(Type type) + { + supportedOnlyIn2(); + if (type == null) + { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.returnType; + preReplaceChild(oldChild, type, RETURN_TYPE_PROPERTY); + this.returnType = type; + postReplaceChild(oldChild, type, RETURN_TYPE_PROPERTY); + } + + /** + * Returns the return type of the method declared in this method + * declaration, exclusive of any extra array dimensions (added in JLS3 API). + * This is one of the few places where the void type is meaningful. + * <p> + * Note that this child is not relevant for constructor declarations + * (although, if present, it does still figure in subtree equality comparisons + * and visits), and is devoid of the binding information ordinarily + * available. In the JLS2 API, the return type is mandatory. + * In the JLS3 API, the return type is optional. + * </p> + * + * @return the return type, possibly the void primitive type, + * or <code>null</code> if none + * @exception UnsupportedOperationException if this operation is used in + * a JLS2 AST + * @since 3.1 + */ + public Type getReturnType2() { + unsupportedIn2(); + if (this.returnType == null && !this.returnType2Initialized) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.returnType == null && !this.returnType2Initialized) { + preLazyInit(); + this.returnType = this.ast.newPrimitiveType(PrimitiveType.VOID); + this.returnType2Initialized = true; + postLazyInit(this.returnType, RETURN_TYPE2_PROPERTY); + } + } + } + return this.returnType; + } + + /** + * Sets the return type of the method declared in this method declaration + * to the given type, exclusive of any extra array dimensions (added in JLS3 API). + * This is one of the few places where the void type is meaningful. + * <p> + * Note that this child is not relevant for constructor declarations + * (although it does still figure in subtree equality comparisons and visits). + * In the JLS2 API, the return type is mandatory. + * In the JLS3 API, the return type is optional. + * </p> + * + * @param type the new return type, possibly the void primitive type, + * or <code>null</code> if none + * @exception UnsupportedOperationException if this operation is used in + * a JLS2 AST + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + * @since 3.1 + */ + public void setReturnType2(Type type) { + unsupportedIn2(); + this.returnType2Initialized = true; + ASTNode oldChild = this.returnType; + preReplaceChild(oldChild, type, RETURN_TYPE2_PROPERTY); + this.returnType = type; + postReplaceChild(oldChild, type, RETURN_TYPE2_PROPERTY); + } + + + int memSize() + { + return BASE_NODE_SIZE + 3 * 4; + } + + int treeSize() + { + return memSize() + + (this.getName() == null ? 0 : getName().treeSize()) + + (this.returnType == null ? 0 : this.returnType.treeSize()) + + this.parameters.listSize() + + this.typeParameters.listSize(); + } + +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Modifier.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Modifier.java new file mode 100644 index 000000000..2d203b305 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Modifier.java @@ -0,0 +1,892 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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 + * $Id: Modifier.java 19895 2009-04-15 13:52:23Z stephan $ + * + * Contributors: + * IBM Corporation - initial API and implementation + * Fraunhofer FIRST - extended API and implementation + * Technical University Berlin - extended API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +/** + * Modifier node. + * <pre> + * Modifier: + * <b>public</b> + * <b>protected</b> + * <b>private</b> + * <b>static</b> + * <b>abstract</b> + * <b>final</b> + * <b>native</b> + * <b>synchronized</b> + * <b>transient</b> + * <b>volatile</b> + * <b>strictfp</b> + * </pre> + * <p> + * The numeric values of these flags match the ones for class + * files as described in the Java Virtual Machine Specification. + * Note that Java model class {@link org.eclipse.jdt.core.Flags} also + * provides the same constants as this class. + * </p> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public final class Modifier extends ASTNode implements IExtendedModifier { + + /** + * Modifier keywords (typesafe enumeration). + * @since 3.0 + */ + public static class ModifierKeyword { + + /** "abstract" modifier with flag value {@link Modifier#ABSTRACT}. */ + public static final ModifierKeyword ABSTRACT_KEYWORD = new ModifierKeyword("abstract", ABSTRACT);//$NON-NLS-1$ + + /** "final" modifier with flag value {@link Modifier#FINAL}. */ + public static final ModifierKeyword FINAL_KEYWORD = new ModifierKeyword("final", FINAL);//$NON-NLS-1$ + + /** + * Map from token to operator (key type: <code>String</code>; + * value type: <code>Operator</code>). + */ + private static final Map KEYWORDS; + + /** "native" modifier with flag value {@link Modifier#NATIVE}. */ + public static final ModifierKeyword NATIVE_KEYWORD = new ModifierKeyword("native", NATIVE);//$NON-NLS-1$ + + /** "private" modifier with flag value {@link Modifier#PRIVATE}. */ + public static final ModifierKeyword PRIVATE_KEYWORD = new ModifierKeyword("private", PRIVATE);//$NON-NLS-1$ + + /** "protected" modifier with flag value {@link Modifier#PROTECTED}. */ + public static final ModifierKeyword PROTECTED_KEYWORD = new ModifierKeyword("protected", PROTECTED);//$NON-NLS-1$ + + /** "public" modifier with flag value {@link Modifier#PUBLIC}. */ + public static final ModifierKeyword PUBLIC_KEYWORD = new ModifierKeyword("public", PUBLIC);//$NON-NLS-1$ + + /** "static" modifier with flag value {@link Modifier#STATIC}. */ + public static final ModifierKeyword STATIC_KEYWORD = new ModifierKeyword("static", STATIC);//$NON-NLS-1$ + + /** "strictfp" modifier with flag value {@link Modifier#STRICTFP}. */ + public static final ModifierKeyword STRICTFP_KEYWORD = new ModifierKeyword("strictfp", STRICTFP);//$NON-NLS-1$ + + /** "synchronized" modifier with flag value {@link Modifier#SYNCHRONIZED}. */ + public static final ModifierKeyword SYNCHRONIZED_KEYWORD = new ModifierKeyword("synchronized", SYNCHRONIZED);//$NON-NLS-1$ + + /** "transient" modifier with flag value {@link Modifier#TRANSIENT}. */ + public static final ModifierKeyword TRANSIENT_KEYWORD = new ModifierKeyword("transient", TRANSIENT);//$NON-NLS-1$ + + /** "volatile" modifier with flag value {@link Modifier#VOLATILE}. */ + public static final ModifierKeyword VOLATILE_KEYWORD = new ModifierKeyword("volatile", VOLATILE);//$NON-NLS-1$ + +//{ObjectTeams: OT-specific callin modifier keywords + public static final ModifierKeyword AFTER_KEYWORD = new ModifierKeyword("after", OT_AFTER_CALLIN);//$NON-NLS-1$ + + public static final ModifierKeyword BEFORE_KEYWORD = new ModifierKeyword("before", OT_BEFORE_CALLIN);//$NON-NLS-1$ + + public static final ModifierKeyword REPLACE_KEYWORD = new ModifierKeyword("replace", OT_REPLACE_CALLIN);//$NON-NLS-1$ + + /** This keyword represents a missing callin-modifier in a callin binding. */ + public static final ModifierKeyword MISSING_KEYWORD = new ModifierKeyword("<missing modifier>", OT_MISSING_MODIFIER);//$NON-NLS-1$ + + /** "get" modifier with flag value {@link Modifier#OT_GET_CALLOUT}. */ + public static final ModifierKeyword GET_KEYWORD = new ModifierKeyword("get", OT_GET_CALLOUT);//$NON-NLS-1$ + + /** "set" modifier with flag value {@link Modifier#OT_SET_CALLOUT}. */ + public static final ModifierKeyword SET_KEYWORD = new ModifierKeyword("set", OT_SET_CALLOUT);//$NON-NLS-1$ + + /** "team" modifier with flag value {@link Modifier#OT_TEAM}. */ + public static final ModifierKeyword TEAM_KEYWORD = new ModifierKeyword("team", OT_TEAM);//$NON-NLS-1$ + + /** "callin" modifier with flag value {@link Modifier#OT_CALLIN}. */ + public static final ModifierKeyword CALLIN_KEYWORD = new ModifierKeyword("callin", OT_CALLIN);//$NON-NLS-1$ +//gbr} + + /** + * Map from token to operator (key type: <code>String</code>; + * value type: <code>Operator</code>). + */ + + static { + KEYWORDS = new HashMap(20); + ModifierKeyword[] ops = { + PUBLIC_KEYWORD, + PROTECTED_KEYWORD, + PRIVATE_KEYWORD, + STATIC_KEYWORD, + ABSTRACT_KEYWORD, + FINAL_KEYWORD, + NATIVE_KEYWORD, + SYNCHRONIZED_KEYWORD, + TRANSIENT_KEYWORD, + VOLATILE_KEYWORD, + STRICTFP_KEYWORD, +//{ObjectTeams: added OT-specific keywords to array + AFTER_KEYWORD, + BEFORE_KEYWORD, + REPLACE_KEYWORD, + MISSING_KEYWORD, + GET_KEYWORD, + SET_KEYWORD, + TEAM_KEYWORD, + CALLIN_KEYWORD +//gbr} + }; + for (int i = 0; i < ops.length; i++) { + KEYWORDS.put(ops[i].toString(), ops[i]); + } + } + + /** + * Returns the modifier corresponding to the given single-bit flag value, + * or <code>null</code> if none or if more than one bit is set. + * <p> + * <code>fromFlagValue</code> is the converse of <code>toFlagValue</code>: + * that is, <code>ModifierKind.fromFlagValue(k.toFlagValue()) == k</code> for + * all modifier keywords <code>k</code>. + * </p> + * + * @param flagValue the single-bit flag value for the modifier + * @return the modifier keyword, or <code>null</code> if none + * @see #toFlagValue() + */ + public static ModifierKeyword fromFlagValue(int flagValue) { + for (Iterator it = KEYWORDS.values().iterator(); it.hasNext(); ) { + ModifierKeyword k = (ModifierKeyword) it.next(); + if (k.toFlagValue() == flagValue) { + return k; + } + } + return null; + } + + /** + * Returns the modifier corresponding to the given string, + * or <code>null</code> if none. + * <p> + * <code>toKeyword</code> is the converse of <code>toString</code>: + * that is, <code>ModifierKind.toKeyword(k.toString()) == k</code> for + * all modifier keywords <code>k</code>. + * </p> + * + * @param keyword the lowercase string name for the modifier + * @return the modifier keyword, or <code>null</code> if none + * @see #toString() + */ + public static ModifierKeyword toKeyword(String keyword) { + return (ModifierKeyword) KEYWORDS.get(keyword); + } + + /** + * The flag value for the modifier. + */ + private int flagValue; + + /** + * The keyword modifier string. + */ + private String keyword; + + /** + * Creates a new modifier with the given keyword. + * <p> + * Note: this constructor is private. The only instances + * ever created are the ones for the standard modifiers. + * </p> + * + * @param keyword the character sequence for the modifier + * @param flagValue flag value as described in the Java Virtual Machine Specification + */ + private ModifierKeyword(String keyword, int flagValue) { + this.keyword = keyword; + this.flagValue = flagValue; + } + + /** + * Returns the modifier flag value corresponding to this modifier keyword. + * These flag values are as described in the Java Virtual Machine Specification. + * + * @return one of the <code>Modifier</code> constants + * @see #fromFlagValue(int) + */ + public int toFlagValue() { + return this.flagValue; + } + + /** + * Returns the keyword for the modifier. + * + * @return the keyword for the modifier + * @see #toKeyword(String) + */ + public String toString() { + return this.keyword; + } + } + + /** + * "abstract" modifier constant (bit mask). + * Applicable to types and methods. + * @since 2.0 + */ + public static final int ABSTRACT = 0x0400; + + /** + * "final" modifier constant (bit mask). + * Applicable to types, methods, fields, and variables. + * @since 2.0 + */ + public static final int FINAL = 0x0010; + + /** + * The "keyword" structural property of this node type. + * @since 3.0 + */ + public static final SimplePropertyDescriptor KEYWORD_PROPERTY = + new SimplePropertyDescriptor(Modifier.class, "keyword", Modifier.ModifierKeyword.class, MANDATORY); //$NON-NLS-1$ + + /** + * "native" modifier constant (bit mask). + * Applicable only to methods. + * @since 2.0 + */ + public static final int NATIVE = 0x0100; + + /** + * Modifier constant (bit mask, value 0) indicating no modifiers. + * @since 2.0 + */ + public static final int NONE = 0x0000; + + /** + * "private" modifier constant (bit mask). + * Applicable to types, methods, constructors, and fields. + * @since 2.0 + */ + public static final int PRIVATE = 0x0002; + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + /** + * "protected" modifier constant (bit mask). + * Applicable to types, methods, constructors, and fields. + * @since 2.0 + */ + public static final int PROTECTED = 0x0004; + + /** + * "public" modifier constant (bit mask). + * Applicable to types, methods, constructors, and fields. + * @since 2.0 + */ + public static final int PUBLIC = 0x0001; + + /** + * "static" modifier constant (bit mask). + * Applicable to types, methods, fields, and initializers. + * @since 2.0 + */ + public static final int STATIC = 0x0008; + + /** + * "strictfp" modifier constant (bit mask). + * Applicable to types and methods. + * @since 2.0 + */ + public static final int STRICTFP = 0x0800; + + /** + * "synchronized" modifier constant (bit mask). + * Applicable only to methods. + * @since 2.0 + */ + public static final int SYNCHRONIZED = 0x0020; + + /** + * "transient" modifier constant (bit mask). + * Applicable only to fields. + * @since 2.0 + */ + public static final int TRANSIENT = 0x0080; + + /** + * "volatile" modifier constant (bit mask). + * Applicable only to fields. + * @since 2.0 + */ + public static final int VOLATILE = 0x0040; + + /** + * "callin" OT-specific modifier constant (bit mask). + * Applicable to methods only ("callin" modifier). + */ + public static final int OT_CALLIN = 0x80000000; // keep in sync with ExtraCompilerModifiers! + + /** + * "team" OT-specific modifier constant (bit mask). + * Applicable to types and methods. + */ + public static final int OT_TEAM = 0x8000; // bit 16 + +//{ObjectTeams: OT-specific callin modifier constants + // Note(SH): please note, that these modifiers differ from all others in this list, + // since they cannot be applied a class, a method, nor a field. + // I find it misleading to place them in this file alltogether. + + /** + * OT-specific modifier constant. + * Applicable only to CallinMappingDeclaration. + */ + public static final int OT_REPLACE_CALLIN = 0x1000; // bit 13 + + /** Used when no callin modifier is present. */ + public static final int OT_MISSING_MODIFIER = 0x2000; // bit 14 + + /** + * OT-specific modifier constant. + * Applicable only to CallinMappingDeclaration. + */ + public static final int OT_BEFORE_CALLIN = 0x4000; // bit 15 + + /** + * OT-specific modifier constant. + * Applicable only to CallinMappingDeclaration. + */ + public static final int OT_AFTER_CALLIN = 0x10000; // bit 17 + + /** + * OT-specific modifier constant. + * Applicable only to callout to field (FieldAccessSpec). + */ + public static final int OT_GET_CALLOUT = 0x20000; // bit 18 + + /** + * OT-specific modifier constant. + * Applicable only to callout to field (FieldAccessSpec). + */ + public static final int OT_SET_CALLOUT = 0x40000; // bit 19 + +//gbr} + + static { + List properyList = new ArrayList(2); + createPropertyList(Modifier.class, properyList); + addProperty(KEYWORD_PROPERTY, properyList); + PROPERTY_DESCRIPTORS = reapPropertyList(properyList); + } + + /** + * Returns whether the given flags includes the "abstract" modifier. + * Applicable to types and methods. + * + * @param flags the modifier flags + * @return <code>true</code> if the <code>ABSTRACT</code> bit is + * set, and <code>false</code> otherwise + * @since 2.0 + */ + public static boolean isAbstract(int flags) { + return (flags & ABSTRACT) != 0; + } + + /** + * Returns whether the given flags includes the "final" modifier. + * Applicable to types, methods, fields, and variables. + * + * @param flags the modifier flags + * @return <code>true</code> if the <code>FINAL</code> bit is + * set, and <code>false</code> otherwise + * @since 2.0 + */ + public static boolean isFinal(int flags) { + return (flags & FINAL) != 0; + } + + /** + * Returns whether the given flags includes the "native" modifier. + * Applicable only to methods. + * + * @param flags the modifier flags + * @return <code>true</code> if the <code>NATIVE</code> bit is + * set, and <code>false</code> otherwise + * @since 2.0 + */ + public static boolean isNative(int flags) { + return (flags & NATIVE) != 0; + } + + /** + * Returns whether the given flags includes the "private" modifier. + * Applicable to types, methods, constructors, and fields. + * + * @param flags the modifier flags + * @return <code>true</code> if the <code>PRIVATE</code> bit is + * set, and <code>false</code> otherwise + * @since 2.0 + */ + public static boolean isPrivate(int flags) { + return (flags & PRIVATE) != 0; + } + + /** + * Returns whether the given flags includes the "protected" modifier. + * Applicable to types, methods, constructors, and fields. + * + * @param flags the modifier flags + * @return <code>true</code> if the <code>PROTECTED</code> bit is + * set, and <code>false</code> otherwise + * @since 2.0 + */ + public static boolean isProtected(int flags) { + return (flags & PROTECTED) != 0; + } + + /** + * Returns whether the given flags includes the "public" modifier. + * Applicable to types, methods, constructors, and fields. + * + * @param flags the modifier flags + * @return <code>true</code> if the <code>PUBLIC</code> bit is + * set, and <code>false</code> otherwise + * @since 2.0 + */ + public static boolean isPublic(int flags) { + return (flags & PUBLIC) != 0; + } + + /** + * Returns whether the given flags includes the "static" modifier. + * Applicable to types, methods, fields, and initializers. + * + * @param flags the modifier flags + * @return <code>true</code> if the <code>STATIC</code> bit is + * set, and <code>false</code> otherwise + * @since 2.0 + */ + public static boolean isStatic(int flags) { + return (flags & STATIC) != 0; + } + + /** + * Returns whether the given flags includes the "strictfp" modifier. + * Applicable to types and methods. + * + * @param flags the modifier flags + * @return <code>true</code> if the <code>STRICTFP</code> bit is + * set, and <code>false</code> otherwise + * @since 2.0 + */ + public static boolean isStrictfp(int flags) { + return (flags & STRICTFP) != 0; + } + + /** + * Returns whether the given flags includes the "synchronized" modifier. + * Applicable only to methods. + * + * @param flags the modifier flags + * @return <code>true</code> if the <code>SYNCHRONIZED</code> bit is + * set, and <code>false</code> otherwise + * @since 2.0 + */ + public static boolean isSynchronized(int flags) { + return (flags & SYNCHRONIZED) != 0; + } + + /** + * Returns whether the given flags includes the "transient" modifier. + * Applicable only to fields. + * + * @param flags the modifier flags + * @return <code>true</code> if the <code>TRANSIENT</code> bit is + * set, and <code>false</code> otherwise + * @since 2.0 + */ + public static boolean isTransient(int flags) { + return (flags & TRANSIENT) != 0; + } + + /** + * Returns whether the given flags includes the "volatile" modifier. + * Applicable only to fields. + * + * @param flags the modifier flags + * @return <code>true</code> if the <code>VOLATILE</code> bit is + * set, and <code>false</code> otherwise + * @since 2.0 + */ + public static boolean isVolatile(int flags) { + return (flags & VOLATILE) != 0; + } + +//{ObjectTeams: OT-specific check methods + /** + * Returns whether the given flags contain the "replace" modifier. + * + * @param flags the modifier flags + * @return <code>true</code> if the <code>REPLACE</code> bit is + * set, and <code>false</code> otherwise + */ + public static boolean isReplace(int flags) + { + return (flags & OT_REPLACE_CALLIN) != 0; + } + + /** + * Returns whether the given flags contain the "before" modifier. + * + * @param flags the modifier flags + * @return <code>true</code> if the <code>BEFORE</code> bit is + * set, and <code>false</code> otherwise + */ + public static boolean isBefore(int flags) + { + return (flags & OT_BEFORE_CALLIN) != 0; + } + + /** + * Returns whether the given flags contain the "after" modifier. + * + * @param flags the modifier flags + * @return <code>true</code> if the <code>AFTER</code> bit is + * set, and <code>false</code> otherwise + */ + public static boolean isAfter(int flags) + { + return (flags & OT_AFTER_CALLIN) != 0; + } + + /** + * Returns whether the given flags includes the "get" modifier. + * Applicable base fields. + * + * @param flags the modifier flags + * @return <code>true</code> if the <code>GET</code> bit is + * set, and <code>false</code> otherwise + */ + public static boolean isGet(int flags) + { + return (flags & OT_GET_CALLOUT) != 0; + } + + /** + * Returns whether the given flags includes the "set" modifier. + * Applicable base fields. + * + * @param flags the modifier flags + * @return <code>true</code> if the <code>SET</code> bit is + * set, and <code>false</code> otherwise + */ + public static boolean isSet(int flags) + { + return (flags & OT_SET_CALLOUT) != 0; + } + + /** + * Returns whether the given flags includes the "team" modifier. + * Applicable base fields. + * + * @param flags the modifier flags + * @return <code>true</code> if the <code>SET</code> bit is + * set, and <code>false</code> otherwise + */ + public static boolean isTeam(int flags) + { + return (flags & OT_TEAM) != 0; + } + + /** + * Returns whether the given flags includes the "callin" modifier. + * Applicable to methods only. + * + * @param flags the modifier flags + * @return <code>true</code> if the <code>AccCallin</code> bit is + * set, and <code>false</code> otherwise + */ + public static boolean isCallin(int flags) + { + return (flags & OT_CALLIN) != 0; + } + +//gbr} + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The modifier keyword; defaults to an unspecified modifier. + * @since 3.0 + */ + private ModifierKeyword modifierKeyword = ModifierKeyword.PUBLIC_KEYWORD; + + /** + * Creates a new unparented modifier node owned by the given AST. + * By default, the node has unspecified (but legal) modifier. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + * @since 3.0 + */ + Modifier(AST ast) { + super(ast); + unsupportedIn2(); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + * @since 3.0 + */ + void accept0(ASTVisitor visitor) { + visitor.visit(this); + visitor.endVisit(this); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + * @since 3.0 + */ + ASTNode clone0(AST target) { + Modifier result = new Modifier(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setKeyword(getKeyword()); + return result; + } + + /** + * Returns the modifier keyword of this modifier node. + * + * @return the modifier keyword + * @since 3.0 + */ + public ModifierKeyword getKeyword() { + return this.modifierKeyword; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + * @since 3.0 + */ + final int getNodeType0() { + return MODIFIER; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final Object internalGetSetObjectProperty(SimplePropertyDescriptor property, boolean get, Object value) { + if (property == KEYWORD_PROPERTY) { + if (get) { + return getKeyword(); + } else { + setKeyword((ModifierKeyword) value); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetObjectProperty(property, get, value); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /** + * Answer true if the receiver is the abstract modifier, false otherwise. + * + * @return true if the receiver is the abstract modifier, false otherwise + * @since 3.2 + */ + public boolean isAbstract() { + return this.modifierKeyword == ModifierKeyword.ABSTRACT_KEYWORD; + } + + /** + * @see IExtendedModifier#isAnnotation() + */ + public boolean isAnnotation() { + return false; + } + + /** + * Answer true if the receiver is the final modifier, false otherwise. + * + * @return true if the receiver is the final modifier, false otherwise + * @since 3.2 + */ + public boolean isFinal() { + return this.modifierKeyword == ModifierKeyword.FINAL_KEYWORD; + } + + /** + * @see IExtendedModifier#isModifier() + */ + public boolean isModifier() { + return true; + } + + /** + * Answer true if the receiver is the native modifier, false otherwise. + * + * @return true if the receiver is the native modifier, false otherwise + * @since 3.2 + */ + public boolean isNative() { + return this.modifierKeyword == ModifierKeyword.NATIVE_KEYWORD; + } + + /** + * Answer true if the receiver is the private modifier, false otherwise. + * + * @return true if the receiver is the private modifier, false otherwise + * @since 3.2 + */ + public boolean isPrivate() { + return this.modifierKeyword == ModifierKeyword.PRIVATE_KEYWORD; + } + + /** + * Answer true if the receiver is the protected modifier, false otherwise. + * + * @return true if the receiver is the protected modifier, false otherwise + * @since 3.2 + */ + public boolean isProtected() { + return this.modifierKeyword == ModifierKeyword.PROTECTED_KEYWORD; + } + + /** + * Answer true if the receiver is the public modifier, false otherwise. + * + * @return true if the receiver is the public modifier, false otherwise + * @since 3.2 + */ + public boolean isPublic() { + return this.modifierKeyword == ModifierKeyword.PUBLIC_KEYWORD; + } + + /** + * Answer true if the receiver is the static modifier, false otherwise. + * + * @return true if the receiver is the static modifier, false otherwise + * @since 3.2 + */ + public boolean isStatic() { + return this.modifierKeyword == ModifierKeyword.STATIC_KEYWORD; + } + + /** + * Answer true if the receiver is the strictfp modifier, false otherwise. + * + * @return true if the receiver is the strictfp modifier, false otherwise + * @since 3.2 + */ + public boolean isStrictfp() { + return this.modifierKeyword == ModifierKeyword.STRICTFP_KEYWORD; + } + + /** + * Answer true if the receiver is the synchronized modifier, false otherwise. + * + * @return true if the receiver is the synchronized modifier, false otherwise + * @since 3.2 + */ + public boolean isSynchronized() { + return this.modifierKeyword == ModifierKeyword.SYNCHRONIZED_KEYWORD; + } + + /** + * Answer true if the receiver is the transient modifier, false otherwise. + * + * @return true if the receiver is the transient modifier, false otherwise + * @since 3.2 + */ + public boolean isTransient() { + return this.modifierKeyword == ModifierKeyword.TRANSIENT_KEYWORD; + } + + /** + * Answer true if the receiver is the volatile modifier, false otherwise. + * + * @return true if the receiver is the volatile modifier, false otherwise + * @since 3.2 + */ + public boolean isVolatile() { + return this.modifierKeyword == ModifierKeyword.VOLATILE_KEYWORD; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + * @since 3.0 + */ + int memSize() { + // treat ModifierKeyword as free + return BASE_NODE_SIZE + 1 * 4; + } + + /** + * Sets the modifier keyword of this modifier node. + * + * @param modifierKeyord the modifier keyword + * @exception IllegalArgumentException if the argument is <code>null</code> + * @since 3.0 + */ + public void setKeyword(ModifierKeyword modifierKeyord) { + if (modifierKeyord == null) { + throw new IllegalArgumentException(); + } + preValueChange(KEYWORD_PROPERTY); + this.modifierKeyword = modifierKeyord; + postValueChange(KEYWORD_PROPERTY); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + * @since 3.0 + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + * @since 3.0 + */ + int treeSize() { + return memSize(); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Name.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Name.java new file mode 100644 index 000000000..9e5de82b8 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Name.java @@ -0,0 +1,119 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +/** + * Abstract base class for all AST nodes that represent names. + * There are exactly two kinds of name: simple ones + * (<code>SimpleName</code>) and qualified ones (<code>QualifiedName</code>). + * <p> + * <pre> + * Name: + * SimpleName + * QualifiedName + * </pre> + * </p> + * + * @since 2.0 + * @noextend This class is not intended to be subclassed by clients. + */ +public abstract class Name extends Expression implements IDocElement { + + /** + * Approximate base size of an expression node instance in bytes, + * including object header and instance fields. + */ + static final int BASE_NAME_NODE_SIZE = BASE_NODE_SIZE + 1 * 4; + + /** + * This index represents the position inside a qualified name. + */ + int index; + + /** + * Creates a new AST node for a name owned by the given AST. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + Name(AST ast) { + super(ast); + } + + /** + * Returns whether this name is a simple name + * (<code>SimpleName</code>). + * + * @return <code>true</code> if this is a simple name, and + * <code>false</code> otherwise + */ + public final boolean isSimpleName() { + return (this instanceof SimpleName); + } + + /** + * Returns whether this name is a qualified name + * (<code>QualifiedName</code>). + * + * @return <code>true</code> if this is a qualified name, and + * <code>false</code> otherwise + */ + public final boolean isQualifiedName() { + return (this instanceof QualifiedName); + } + + /** + * Resolves and returns the binding for the entity referred to by this name. + * <p> + * Note that bindings are generally unavailable unless requested when the + * AST is being built. + * </p> + * + * @return the binding, or <code>null</code> if the binding cannot be + * resolved + */ + public final IBinding resolveBinding() { + return this.ast.getBindingResolver().resolveName(this); + } + + /** + * Returns the standard dot-separated representation of this name. + * If the name is a simple name, the result is the name's identifier. + * If the name is a qualified name, the result is the name of the qualifier + * (as computed by this method) followed by "." followed by the name's + * identifier. + * + * @return the fully qualified name + * @since 3.0 + */ + public final String getFullyQualifiedName() { + if (isSimpleName()) { + // avoid creating garbage for common case + return ((SimpleName) this).getIdentifier(); + } else { + StringBuffer buffer = new StringBuffer(50); + appendName(buffer); + return new String(buffer); + } + } + + /** + * Appends the standard representation of this name to the given string + * buffer. + * + * @param buffer the buffer + * @since 3.0 + */ + abstract void appendName(StringBuffer buffer); +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/NodeEventHandler.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/NodeEventHandler.java new file mode 100644 index 000000000..a0878837d --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/NodeEventHandler.java @@ -0,0 +1,188 @@ +/******************************************************************************* + * Copyright (c) 2004, 2009 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.dom; + +/** + * A node event handler is an internal mechanism for receiving + * notification of changes to nodes in an AST. + * <p> + * The default implementation serves as the default event handler + * that does nothing. Internal subclasses do all the real work. + * </p> + * + * @see AST#getEventHandler() + */ +class NodeEventHandler { + + /** + * Creates a node event handler. + */ + NodeEventHandler() { + // default implementation: do nothing + } + + /** + * Reports that the given node is about to lose a child. + * The first half of an event pair. The default implementation does nothing. + * + * @param node the node about to be modified + * @param child the node about to be removed + * @param property the child or child list property descriptor + * @see #postRemoveChildEvent(ASTNode, ASTNode, StructuralPropertyDescriptor) + * @since 3.0 + */ + void preRemoveChildEvent(ASTNode node, ASTNode child, StructuralPropertyDescriptor property) { + // do nothing + // System.out.println("DEL1 " + property); + } + + /** + * Reports that the given node has just lose a child. + * The second half of an event pair. The default implementation does nothing. + * + * @param node the node that was modified + * @param child the child that was removed; note that this node is unparented + * @param property the child or child list property descriptor + * @see #preRemoveChildEvent(ASTNode, ASTNode, StructuralPropertyDescriptor) + * @since 3.0 + */ + void postRemoveChildEvent(ASTNode node, ASTNode child, StructuralPropertyDescriptor property) { + // do nothing + // System.out.println("DEL2 " + property); + } + + /** + * Reports that the given node is about to have a child replaced. + * The first half of an event pair. + * The default implementation does nothing. + * + * @param node the node about to be modified + * @param child the node about to be replaced + * @param newChild the replacement child; note that this node is unparented + * @param property the child or child list property descriptor + * @see #preReplaceChildEvent(ASTNode, ASTNode, ASTNode, StructuralPropertyDescriptor) + * @since 3.0 + */ + void preReplaceChildEvent(ASTNode node, ASTNode child, ASTNode newChild, StructuralPropertyDescriptor property) { + // do nothing + // System.out.println("REP1 " + property); + } + + /** + * Reports that the given node has had its child replaced. The second half + * of an event pair. The default implementation does nothing. + * + * @param node the node that was modified + * @param child the node that was replaced; note that this node is unparented + * @param newChild the replacement child + * @param property the child or child list property descriptor + * @see #postReplaceChildEvent(ASTNode, ASTNode, ASTNode, StructuralPropertyDescriptor) + * @since 3.0 + */ + void postReplaceChildEvent(ASTNode node, ASTNode child, ASTNode newChild, StructuralPropertyDescriptor property) { + // do nothing + // System.out.println("REP2 " + property); + } + + /** + * Reports that the given node is about to gain a child. + * The first half of an event pair. The default implementation does nothing. + * + * @param node the node that to be modified + * @param child the node that is to be added as a child; note that this + * node is unparented; in the case of a child list property, the exact + * location of insertion is not supplied (but is known on the + * corresponding <code>postAddChildEvent</code> to + * follow) + * @param property the child or child list property descriptor + * @see #postAddChildEvent(ASTNode, ASTNode, StructuralPropertyDescriptor) + * @since 3.0 + */ + void preAddChildEvent(ASTNode node, ASTNode child, StructuralPropertyDescriptor property) { + // do nothing + // System.out.println("ADD1 " + property); + } + + /** + * Reports that the given node has just gained a child. + * The second half of an event pair. The default implementation does nothing. + * + * @param node the node that was modified + * @param child the node that was added as a child + * @param property the child or child list property descriptor + * @see #preAddChildEvent(ASTNode, ASTNode, StructuralPropertyDescriptor) + * @since 3.0 + */ + void postAddChildEvent(ASTNode node, ASTNode child, StructuralPropertyDescriptor property) { + // do nothing + // System.out.println("ADD2 " + property); + } + + /** + * Reports that the given node is about to change the value of a + * non-child property. The first half of an event pair. + * The default implementation does nothing. + * + * @param node the node to be modified + * @param property the property descriptor + * @see #postValueChangeEvent(ASTNode, SimplePropertyDescriptor) + * @since 3.0 + */ + void preValueChangeEvent(ASTNode node, SimplePropertyDescriptor property) { + // do nothing + // System.out.println("MOD1 " + property); + } + + /** + * Reports that the given node has just changed the value of a + * non-child property. The second half of an event pair. + * The default implementation does nothing. + * + * @param node the node that was modified + * @param property the property descriptor + * @see #preValueChangeEvent(ASTNode, SimplePropertyDescriptor) + * @since 3.0 + */ + void postValueChangeEvent(ASTNode node, SimplePropertyDescriptor property) { + // do nothing + // System.out.println("MOD2 " + property); + } + + /** + * Reports that the given node is about to be cloned. + * The first half of an event pair. + * The default implementation does nothing. + * + * @param node the node to be modified + * @see #postCloneNodeEvent(ASTNode, ASTNode) + * @since 3.0 + */ + void preCloneNodeEvent(ASTNode node) { + // do nothing + // System.out.println("CLONE1"); + } + + /** + * Reports that the given node has just been cloned. + * The second half of an event pair. + * The default implementation does nothing. + * + * @param node the node that was modified + * @param clone the clone of <code>node</code> + * @see #preCloneNodeEvent(ASTNode) + * @since 3.0 + */ + void postCloneNodeEvent(ASTNode node, ASTNode clone) { + // do nothing + // System.out.println("CLONE2"); + } + +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/NodeFinder.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/NodeFinder.java new file mode 100644 index 000000000..2cbe00faa --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/NodeFinder.java @@ -0,0 +1,224 @@ +/******************************************************************************* + * Copyright (c) 2000, 2009 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: + * IBM Corporation - initial API and implementation + * Technical University Berlin - extended API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.dom; + +import org.eclipse.jdt.core.IBuffer; +import org.eclipse.jdt.core.ISourceRange; +import org.eclipse.jdt.core.ITypeRoot; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.core.ToolFactory; +import org.eclipse.jdt.core.compiler.IScanner; +import org.eclipse.jdt.core.compiler.ITerminalSymbols; +import org.eclipse.jdt.core.compiler.InvalidInputException; + +/** + * For a given range, finds the covered node and the covering node. + * + * @since 3.5 + */ +public final class NodeFinder { + /** + * This class defines the actual visitor that finds the node. + */ + private static class NodeFinderVisitor extends ASTVisitor { + private int fStart; + private int fEnd; + private ASTNode fCoveringNode; + private ASTNode fCoveredNode; + +//{ObjectTeams: Do not descend into role files: + // The topmost type found during traversal + private TypeDeclaration topType= null; + public boolean visit(TypeDeclaration type) { + if (topType == null) + topType= type; + return super.visit(type); + } + public boolean visit(RoleTypeDeclaration roleType) { + if (this.topType != null && roleType.isRoleFile()) + return false; + if (topType == null) + topType= roleType; + return super.visit(roleType); + } +// SH} + + NodeFinderVisitor(int offset, int length) { + super(true); // include Javadoc tags + this.fStart= offset; + this.fEnd= offset + length; + } + + public boolean preVisit2(ASTNode node) { + int nodeStart= node.getStartPosition(); + int nodeEnd= nodeStart + node.getLength(); + if (nodeEnd < this.fStart || this.fEnd < nodeStart) { + return false; + } + if (nodeStart <= this.fStart && this.fEnd <= nodeEnd) { + this.fCoveringNode= node; + } + if (this.fStart <= nodeStart && nodeEnd <= this.fEnd) { + if (this.fCoveringNode == node) { // nodeStart == fStart && nodeEnd == fEnd + this.fCoveredNode= node; + return true; // look further for node with same length as parent + } else if (this.fCoveredNode == null) { // no better found + this.fCoveredNode= node; + } + return false; + } + return true; + } + /** + * Returns the covered node. If more than one nodes are covered by the selection, the + * returned node is first covered node found in a top-down traversal of the AST + * @return ASTNode + */ + public ASTNode getCoveredNode() { + return this.fCoveredNode; + } + + /** + * Returns the covering node. If more than one nodes are covering the selection, the + * returned node is last covering node found in a top-down traversal of the AST + * @return ASTNode + */ + public ASTNode getCoveringNode() { + return this.fCoveringNode; + } + } + /** + * Maps a selection to a given ASTNode, where the selection is defined using a start and a length. + * The result node is determined as follows: + * <ul> + * <li>first the visitor tries to find a node with the exact <code>start</code> and <code>length</code></li> + * <li>if no such node exists then the node that encloses the range defined by + * <code>start</code> and <code>length</code> is returned.</li> + * <li>if the length is zero then also nodes are considered where the node's + * start or end position matches <code>start</code>.</li> + * <li>otherwise <code>null</code> is returned.</li> + * </ul> + * + * @param root the root node from which the search starts + * @param start the given start + * @param length the given length + * + * @return the found node + */ + public static ASTNode perform(ASTNode root, int start, int length) { + NodeFinder finder = new NodeFinder(root, start, length); + ASTNode result= finder.getCoveredNode(); + if (result == null || result.getStartPosition() != start || result.getLength() != length) { + return finder.getCoveringNode(); + } + return result; + } + + /** + * Maps a selection to a given ASTNode, where the selection is defined using a source range. + * It calls <code>perform(root, range.getOffset(), range.getLength())</code>. + * + * @return the result node + * @see #perform(ASTNode, int, int) + */ + public static ASTNode perform(ASTNode root, ISourceRange range) { + return perform(root, range.getOffset(), range.getLength()); + } + + /** + * Maps a selection to a given ASTNode, where the selection is given by a start and a length. + * The result node is determined as follows: + * <ul> + * <li>first the visitor tries to find a node that is covered by <code>start</code> and + * <code>length</code> where either <code>start</code> and <code>length</code> exactly + * matches the node or where the text covered before and after the node only consists + * of white spaces or comments.</li> + * <li>if no such node exists then the node that encloses the range defined by + * <code>start</code> and <code>length</code> is returned.</li> + * <li>if the length is zero then also nodes are considered where the node's + * start or end position matches <code>start</code>.</li> + * <li>otherwise <code>null</code> is returned.</li> + * </ul> + * + * @param root the root node from which the search starts + * @param start the given start + * @param length the given length + * @param source the source of the compilation unit + * + * @return the result node + * @throws JavaModelException if an error occurs in the Java model + */ + public static ASTNode perform(ASTNode root, int start, int length, ITypeRoot source) throws JavaModelException { + NodeFinder finder = new NodeFinder(root, start, length); + ASTNode result= finder.getCoveredNode(); + if (result == null) + return null; + int nodeStart= result.getStartPosition(); + if (start <= nodeStart && ((nodeStart + result.getLength()) <= (start + length))) { + IBuffer buffer= source.getBuffer(); + if (buffer != null) { + IScanner scanner= ToolFactory.createScanner(false, false, false, false); + scanner.setSource(buffer.getText(start, length).toCharArray()); + try { + int token= scanner.getNextToken(); + if (token != ITerminalSymbols.TokenNameEOF) { + int tStart= scanner.getCurrentTokenStartPosition(); + if (tStart == result.getStartPosition() - start) { + scanner.resetTo(tStart + result.getLength(), length - 1); + token= scanner.getNextToken(); + if (token == ITerminalSymbols.TokenNameEOF) + return result; + } + } + } catch (InvalidInputException e) { + // ignore + } + } + } + return finder.getCoveringNode(); + } + private ASTNode fCoveringNode; + private ASTNode fCoveredNode; + + /** + * Instantiate a new node finder using the given root node, the given start and the given length. + * + * @param root the given root node + * @param start the given start + * @param length the given length + */ + public NodeFinder(ASTNode root, int start, int length) { + NodeFinderVisitor nodeFinderVisitor = new NodeFinderVisitor(start, length); + root.accept(nodeFinderVisitor); + this.fCoveredNode = nodeFinderVisitor.getCoveredNode(); + this.fCoveringNode = nodeFinderVisitor.getCoveringNode(); + } + /** + * Returns the covered node. If more than one nodes are covered by the selection, the + * returned node is first covered node found in a top-down traversal of the AST. + * + * @return the covered node + */ + public ASTNode getCoveredNode() { + return this.fCoveredNode; + } + + /** + * Returns the covering node. If more than one nodes are covering the selection, the + * returned node is last covering node found in a top-down traversal of the AST. + * + * @return the covering node + */ + public ASTNode getCoveringNode() { + return this.fCoveringNode; + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/NodeSearcher.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/NodeSearcher.java new file mode 100644 index 000000000..1f070c411 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/NodeSearcher.java @@ -0,0 +1,99 @@ +/******************************************************************************* + * Copyright (c) 2000, 2009 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.dom; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration; +import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; +import org.eclipse.jdt.internal.compiler.ast.Initializer; +import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration; +import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; +import org.eclipse.jdt.internal.compiler.lookup.ClassScope; +import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope; +import org.eclipse.jdt.internal.compiler.lookup.MethodScope; + +class NodeSearcher extends ASTVisitor { + public org.eclipse.jdt.internal.compiler.ast.ASTNode found; + public TypeDeclaration enclosingType; + public int position; + + NodeSearcher(int position) { + this.position = position; + } + + public boolean visit( + ConstructorDeclaration constructorDeclaration, + ClassScope scope) { + + if (constructorDeclaration.declarationSourceStart <= this.position + && this.position <= constructorDeclaration.declarationSourceEnd) { + this.found = constructorDeclaration; + return false; + } + return true; + } + + public boolean visit( + FieldDeclaration fieldDeclaration, + MethodScope scope) { + if (fieldDeclaration.declarationSourceStart <= this.position + && this.position <= fieldDeclaration.declarationSourceEnd) { + this.found = fieldDeclaration; + return false; + } + return true; + } + + public boolean visit(Initializer initializer, MethodScope scope) { + if (initializer.declarationSourceStart <= this.position + && this.position <= initializer.declarationSourceEnd) { + this.found = initializer; + return false; + } + return true; + } + + public boolean visit( + TypeDeclaration memberTypeDeclaration, + ClassScope scope) { + if (memberTypeDeclaration.declarationSourceStart <= this.position + && this.position <= memberTypeDeclaration.declarationSourceEnd) { + this.enclosingType = memberTypeDeclaration; + return true; + + } + return false; + } + + public boolean visit( + MethodDeclaration methodDeclaration, + ClassScope scope) { + + if (methodDeclaration.declarationSourceStart <= this.position + && this.position <= methodDeclaration.declarationSourceEnd) { + this.found = methodDeclaration; + return false; + } + return true; + } + + public boolean visit( + TypeDeclaration typeDeclaration, + CompilationUnitScope scope) { + if (typeDeclaration.declarationSourceStart <= this.position + && this.position <= typeDeclaration.declarationSourceEnd) { + this.enclosingType = typeDeclaration; + return true; + } + return false; + } + +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/NormalAnnotation.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/NormalAnnotation.java new file mode 100644 index 000000000..dfbc7648a --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/NormalAnnotation.java @@ -0,0 +1,202 @@ +/******************************************************************************* + * Copyright (c) 2004, 2009 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Normal annotation node (added in JLS3 API). + * <p> + * <pre> + * NormalAnnotation: + * <b>@</b> TypeName <b>(</b> [ MemberValuePair { <b>,</b> MemberValuePair } ] <b>)</b> + * </pre> + * </p> + * + * @since 3.1 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public final class NormalAnnotation extends Annotation { + + /** + * The "typeName" structural property of this node type. + */ + public static final ChildPropertyDescriptor TYPE_NAME_PROPERTY = + internalTypeNamePropertyFactory(NormalAnnotation.class); + + /** + * The "values" structural property of this node type. + */ + public static final ChildListPropertyDescriptor VALUES_PROPERTY = + new ChildListPropertyDescriptor(NormalAnnotation.class, "values", MemberValuePair.class, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List propertyList = new ArrayList(3); + createPropertyList(NormalAnnotation.class, propertyList); + addProperty(TYPE_NAME_PROPERTY, propertyList); + addProperty(VALUES_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the AST.JLS* constants + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The list of member value pairs (element type: + * {@link MemberValuePair}). Defaults to an empty list. + */ + private ASTNode.NodeList values = + new ASTNode.NodeList(VALUES_PROPERTY); + + /** + * Creates a new unparented normal annotation node owned + * by the given AST. By default, the annotation has an + * unspecified type name and an empty list of member value + * pairs. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + NormalAnnotation(AST ast) { + super(ast); + unsupportedIn2(); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == TYPE_NAME_PROPERTY) { + if (get) { + return getTypeName(); + } else { + setTypeName((Name) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalGetChildListProperty(ChildListPropertyDescriptor property) { + if (property == VALUES_PROPERTY) { + return values(); + } + // allow default implementation to flag the error + return super.internalGetChildListProperty(property); + } + + /* (omit javadoc for this method) + * Method declared on BodyDeclaration. + */ + final ChildPropertyDescriptor internalTypeNameProperty() { + return TYPE_NAME_PROPERTY; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return NORMAL_ANNOTATION; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + NormalAnnotation result = new NormalAnnotation(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setTypeName((Name) ASTNode.copySubtree(target, getTypeName())); + result.values().addAll(ASTNode.copySubtrees(target, values())); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + acceptChild(visitor, getTypeName()); + acceptChildren(visitor, this.values); + } + visitor.endVisit(this); + } + + /** + * Returns the live list of member value pairs in this annotation. + * Adding and removing nodes from this list affects this node + * dynamically. All nodes in this list must be + * {@link MemberValuePair}s; attempts to add any other + * type of node will trigger an exception. + * + * @return the live list of member value pairs in this + * annotation (element type: <code>MemberValuePair</code>) + */ + public List values() { + return this.values; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return super.memSize() + 1 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.typeName == null ? 0 : getTypeName().treeSize()) + + this.values.listSize(); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/NullLiteral.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/NullLiteral.java new file mode 100644 index 000000000..8bacdf3b3 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/NullLiteral.java @@ -0,0 +1,118 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Null literal node. + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class NullLiteral extends Expression { + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List propertyList = new ArrayList(1); + createPropertyList(NullLiteral.class, propertyList); + PROPERTY_DESCRIPTORS = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * Creates a new unparented null literal node owned by the given AST. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + NullLiteral(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return NULL_LITERAL; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + NullLiteral result = new NullLiteral(target); + result.setSourceRange(getStartPosition(), getLength()); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + visitor.visit(this); + visitor.endVisit(this); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return BASE_NODE_SIZE; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return memSize(); + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/NumberLiteral.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/NumberLiteral.java new file mode 100644 index 000000000..2e38b173c --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/NumberLiteral.java @@ -0,0 +1,223 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jdt.core.compiler.InvalidInputException; +import org.eclipse.jdt.internal.compiler.parser.Scanner; +import org.eclipse.jdt.internal.compiler.parser.TerminalTokens; + +/** + * Number literal nodes. + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class NumberLiteral extends Expression { + + /** + * The "token" structural property of this node type. + * @since 3.0 + */ + public static final SimplePropertyDescriptor TOKEN_PROPERTY = + new SimplePropertyDescriptor(NumberLiteral.class, "token", String.class, MANDATORY); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List propertyList = new ArrayList(2); + createPropertyList(NumberLiteral.class, propertyList); + addProperty(TOKEN_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The token string; defaults to the integer literal "0". + */ + private String tokenValue = "0";//$NON-NLS-1$ + + /** + * Creates a new unparented number literal node owned by the given AST. + * By default, the number literal is the token "<code>0</code>". + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + NumberLiteral(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final Object internalGetSetObjectProperty(SimplePropertyDescriptor property, boolean get, Object value) { + if (property == TOKEN_PROPERTY) { + if (get) { + return getToken(); + } else { + setToken((String) value); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetObjectProperty(property, get, value); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return NUMBER_LITERAL; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + NumberLiteral result = new NumberLiteral(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setToken(getToken()); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + visitor.visit(this); + visitor.endVisit(this); + } + + /** + * Returns the token of this number literal node. The value is the sequence + * of characters that would appear in the source program. + * + * @return the numeric literal token + */ + public String getToken() { + return this.tokenValue; + } + + /** + * Sets the token of this number literal node. The value is the sequence + * of characters that would appear in the source program. + * + * @param token the numeric literal token + * @exception IllegalArgumentException if the argument is incorrect + */ + public void setToken(String token) { + // update internalSetToken(String) if this is changed + if (token == null || token.length() == 0) { + throw new IllegalArgumentException(); + } + Scanner scanner = this.ast.scanner; + char[] source = token.toCharArray(); + scanner.setSource(source); + scanner.resetTo(0, source.length); + scanner.tokenizeComments = false; + scanner.tokenizeWhiteSpace = false; + try { + int tokenType = scanner.getNextToken(); + switch(tokenType) { + case TerminalTokens.TokenNameDoubleLiteral: + case TerminalTokens.TokenNameIntegerLiteral: + case TerminalTokens.TokenNameFloatingPointLiteral: + case TerminalTokens.TokenNameLongLiteral: + break; + case TerminalTokens.TokenNameMINUS : + tokenType = scanner.getNextToken(); + switch(tokenType) { + case TerminalTokens.TokenNameDoubleLiteral: + case TerminalTokens.TokenNameIntegerLiteral: + case TerminalTokens.TokenNameFloatingPointLiteral: + case TerminalTokens.TokenNameLongLiteral: + break; + default: + throw new IllegalArgumentException("Invalid number literal : >" + token + "<"); //$NON-NLS-1$//$NON-NLS-2$ + } + break; + default: + throw new IllegalArgumentException("Invalid number literal : >" + token + "<");//$NON-NLS-1$//$NON-NLS-2$ + } + } catch(InvalidInputException e) { + throw new IllegalArgumentException(); + } finally { + scanner.tokenizeComments = true; + scanner.tokenizeWhiteSpace = true; + } + preValueChange(TOKEN_PROPERTY); + this.tokenValue = token; + postValueChange(TOKEN_PROPERTY); + } + + /* (omit javadoc for this method) + * This method is a copy of setToken(String) that doesn't do any validation. + */ + void internalSetToken(String token) { + preValueChange(TOKEN_PROPERTY); + this.tokenValue = token; + postValueChange(TOKEN_PROPERTY); + } + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + int size = BASE_NODE_SIZE + 1 * 4 + stringSize(this.tokenValue); + return size; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return memSize(); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/PackageBinding.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/PackageBinding.java new file mode 100644 index 000000000..b8f65f8c0 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/PackageBinding.java @@ -0,0 +1,254 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.Iterator; +import java.util.List; +import org.eclipse.jdt.core.ICompilationUnit; +import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.core.IPackageFragment; +import org.eclipse.jdt.core.IPackageFragmentRoot; +import org.eclipse.jdt.core.JavaModelException; + +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.env.IBinaryAnnotation; +import org.eclipse.jdt.internal.compiler.env.IBinaryType; +import org.eclipse.jdt.internal.compiler.env.INameEnvironment; +import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer; +import org.eclipse.jdt.internal.compiler.lookup.BinaryTypeBinding; +import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; +import org.eclipse.jdt.internal.compiler.util.Util; +import org.eclipse.jdt.internal.core.NameLookup; +import org.eclipse.jdt.internal.core.SearchableEnvironment; + +/** + * Internal implementation of package bindings. + */ +class PackageBinding implements IPackageBinding { + + private static final String[] NO_NAME_COMPONENTS = CharOperation.NO_STRINGS; + private static final String UNNAMED = Util.EMPTY_STRING; + private static final char PACKAGE_NAME_SEPARATOR = '.'; + + private org.eclipse.jdt.internal.compiler.lookup.PackageBinding binding; + private String name; + private BindingResolver resolver; + private String[] components; + + PackageBinding(org.eclipse.jdt.internal.compiler.lookup.PackageBinding binding, BindingResolver resolver) { + this.binding = binding; + this.resolver = resolver; + } + + public IAnnotationBinding[] getAnnotations() { + try { + INameEnvironment nameEnvironment = this.binding.environment.nameEnvironment; + if (!(nameEnvironment instanceof SearchableEnvironment)) + return AnnotationBinding.NoAnnotations; + NameLookup nameLookup = ((SearchableEnvironment) nameEnvironment).nameLookup; + if (nameLookup == null) + return AnnotationBinding.NoAnnotations; + final String pkgName = getName(); + IPackageFragment[] pkgs = nameLookup.findPackageFragments(pkgName, false/*exact match*/); + if (pkgs == null) + return AnnotationBinding.NoAnnotations; + + for (int i = 0, len = pkgs.length; i < len; i++) { + int fragType = pkgs[i].getKind(); + switch(fragType) { + case IPackageFragmentRoot.K_SOURCE: + String unitName = "package-info.java"; //$NON-NLS-1$ + ICompilationUnit unit = pkgs[i].getCompilationUnit(unitName); + if (unit != null && unit.exists()) { + ASTParser p = ASTParser.newParser(AST.JLS3); + p.setSource(unit); + p.setResolveBindings(true); + p.setUnitName(unitName); + p.setFocalPosition(0); + p.setKind(ASTParser.K_COMPILATION_UNIT); + CompilationUnit domUnit = (CompilationUnit) p.createAST(null); + PackageDeclaration pkgDecl = domUnit.getPackage(); + if (pkgDecl != null) { + List annos = pkgDecl.annotations(); + if (annos == null || annos.isEmpty()) + return AnnotationBinding.NoAnnotations; + IAnnotationBinding[] result = new IAnnotationBinding[annos.size()]; + int index=0; + for (Iterator it = annos.iterator(); it.hasNext(); index++) { + result[index] = ((Annotation) it.next()).resolveAnnotationBinding(); + // not resolving bindings + if (result[index] == null) + return AnnotationBinding.NoAnnotations; + } + return result; + } + } + break; + case IPackageFragmentRoot.K_BINARY: + NameEnvironmentAnswer answer = + nameEnvironment.findType(TypeConstants.PACKAGE_INFO_NAME, this.binding.compoundName); + if (answer != null && answer.isBinaryType()) { + IBinaryType type = answer.getBinaryType(); + char[][][] missingTypeNames = type.getMissingTypeNames(); + IBinaryAnnotation[] binaryAnnotations = type.getAnnotations(); + org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding[] binaryInstances = + BinaryTypeBinding.createAnnotations(binaryAnnotations, this.binding.environment, missingTypeNames); + org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding[] allInstances = + org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding.addStandardAnnotations(binaryInstances, type.getTagBits(), this.binding.environment); + int total = allInstances.length; + IAnnotationBinding[] domInstances = new AnnotationBinding[total]; + for (int a = 0; a < total; a++) { + final IAnnotationBinding annotationInstance = this.resolver.getAnnotationInstance(allInstances[a]); + if (annotationInstance == null) {// not resolving binding + return AnnotationBinding.NoAnnotations; + } + domInstances[a] = annotationInstance; + } + return domInstances; + } + } + } + } catch(JavaModelException e) { + return AnnotationBinding.NoAnnotations; + } + return AnnotationBinding.NoAnnotations; + } + + /* + * @see IBinding#getName() + */ + public String getName() { + if (this.name == null) { + computeNameAndComponents(); + } + return this.name; + } + + /* + * @see IPackageBinding#isUnnamed() + */ + public boolean isUnnamed() { + return getName().equals(UNNAMED); + } + + /* + * @see IPackageBinding#getNameComponents() + */ + public String[] getNameComponents() { + if (this.components == null) { + computeNameAndComponents(); + } + return this.components; + } + + /* + * @see IBinding#getKind() + */ + public int getKind() { + return IBinding.PACKAGE; + } + + /* + * @see IBinding#getModifiers() + */ + public int getModifiers() { + return Modifier.NONE; + } + + /* + * @see IBinding#isDeprecated() + */ + public boolean isDeprecated() { + return false; + } + + /** + * @see IBinding#isRecovered() + */ + public boolean isRecovered() { + return false; + } + + /** + * @see IBinding#isSynthetic() + */ + public boolean isSynthetic() { + return false; + } + + /* + * @see IBinding#getJavaElement() + */ + public IJavaElement getJavaElement() { + INameEnvironment nameEnvironment = this.binding.environment.nameEnvironment; // a package binding always has a LooupEnvironment set + if (!(nameEnvironment instanceof SearchableEnvironment)) return null; + NameLookup nameLookup = ((SearchableEnvironment) nameEnvironment).nameLookup; + if (nameLookup == null) return null; + IJavaElement[] pkgs = nameLookup.findPackageFragments(getName(), false/*exact match*/); + if (pkgs == null) return null; + return pkgs[0]; + } + + /* + * @see IBinding#getKey() + */ + public String getKey() { + return new String(this.binding.computeUniqueKey()); + } + + /* + * @see IBinding#isEqualTo(Binding) + * @since 3.1 + */ + public boolean isEqualTo(IBinding other) { + if (other == this) { + // identical binding - equal (key or no key) + return true; + } + if (other == null) { + // other binding missing + return false; + } + if (!(other instanceof PackageBinding)) { + return false; + } + org.eclipse.jdt.internal.compiler.lookup.PackageBinding packageBinding2 = ((PackageBinding) other).binding; + return CharOperation.equals(this.binding.compoundName, packageBinding2.compoundName); + } + + private void computeNameAndComponents() { + char[][] compoundName = this.binding.compoundName; + if (compoundName == CharOperation.NO_CHAR_CHAR || compoundName == null) { + this.name = UNNAMED; + this.components = NO_NAME_COMPONENTS; + } else { + int length = compoundName.length; + this.components = new String[length]; + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < length - 1; i++) { + this.components[i] = new String(compoundName[i]); + buffer.append(compoundName[i]).append(PACKAGE_NAME_SEPARATOR); + } + this.components[length - 1] = new String(compoundName[length - 1]); + buffer.append(compoundName[length - 1]); + this.name = buffer.toString(); + } + } + + /* + * For debugging purpose only. + * @see java.lang.Object#toString() + */ + public String toString() { + return this.binding.toString(); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/PackageDeclaration.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/PackageDeclaration.java new file mode 100644 index 000000000..8c8d3a0a3 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/PackageDeclaration.java @@ -0,0 +1,362 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Package declaration AST node type. + * For JLS2: + * <pre> + * PackageDeclaration: + * <b>package</b> Name <b>;</b> + * </pre> + * For JLS3, annotations and doc comment + * were added: + * <pre> + * PackageDeclaration: + * [ Javadoc ] { Annotation } <b>package</b> Name <b>;</b> + * </pre> + * Note that the standard AST parser only recognizes a Javadoc comment + * immediately preceding the package declaration when it occurs in the + * special <code>package-info.java</code> compilation unit (JLS3 7.4.1.1). + * The Javadoc comment in that file contains the package description. + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class PackageDeclaration extends ASTNode { + + /** + * The "javadoc" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor JAVADOC_PROPERTY = + new ChildPropertyDescriptor(PackageDeclaration.class, "javadoc", Javadoc.class, OPTIONAL, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "annotations" structural property of this node type (added in JLS3 API). + * @since 3.1 + */ + public static final ChildListPropertyDescriptor ANNOTATIONS_PROPERTY = + new ChildListPropertyDescriptor(PackageDeclaration.class, "annotations", Annotation.class, CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "name" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor NAME_PROPERTY = + new ChildPropertyDescriptor(PackageDeclaration.class, "name", Name.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + * @since 3.0 + */ + private static final List PROPERTY_DESCRIPTORS_2_0; + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + * @since 3.1 + */ + private static final List PROPERTY_DESCRIPTORS_3_0; + + static { + List propertyList = new ArrayList(2); + createPropertyList(PackageDeclaration.class, propertyList); + addProperty(NAME_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS_2_0 = reapPropertyList(propertyList); + + propertyList = new ArrayList(4); + createPropertyList(PackageDeclaration.class, propertyList); + addProperty(JAVADOC_PROPERTY, propertyList); + addProperty(ANNOTATIONS_PROPERTY, propertyList); + addProperty(NAME_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS_3_0 = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + if (apiLevel == AST.JLS2_INTERNAL) { + return PROPERTY_DESCRIPTORS_2_0; + } else { + return PROPERTY_DESCRIPTORS_3_0; + } + } + + /** + * The doc comment, or <code>null</code> if none. + * Defaults to none. + * @since 3.0 + */ + Javadoc optionalDocComment = null; + + /** + * The annotations (element type: <code>Annotation</code>). + * Null in JLS2. Added in JLS3; defaults to an empty list + * (see constructor). + * @since 3.1 + */ + private ASTNode.NodeList annotations = null; + + /** + * The package name; lazily initialized; defaults to a unspecified, + * legal Java package identifier. + */ + private Name packageName = null; + + /** + * Creates a new AST node for a package declaration owned by the + * given AST. The package declaration initially has an unspecified, + * but legal, Java identifier; and an empty list of annotations. + * <p> + * N.B. This constructor is package-private; all subclasses must be + * declared in the same package; clients are unable to declare + * additional subclasses. + * </p> + * + * @param ast the AST that is to own this node + */ + PackageDeclaration(AST ast) { + super(ast); + if (ast.apiLevel >= AST.JLS3) { + this.annotations = new ASTNode.NodeList(ANNOTATIONS_PROPERTY); + } + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == JAVADOC_PROPERTY) { + if (get) { + return getJavadoc(); + } else { + setJavadoc((Javadoc) child); + return null; + } + } + if (property == NAME_PROPERTY) { + if (get) { + return getName(); + } else { + setName((Name) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalGetChildListProperty(ChildListPropertyDescriptor property) { + if (property == ANNOTATIONS_PROPERTY) { + return annotations(); + } + // allow default implementation to flag the error + return super.internalGetChildListProperty(property); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return PACKAGE_DECLARATION; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + PackageDeclaration result = new PackageDeclaration(target); + result.setSourceRange(getStartPosition(), getLength()); + if (this.ast.apiLevel >= AST.JLS3) { + result.setJavadoc((Javadoc) ASTNode.copySubtree(target, getJavadoc())); + result.annotations().addAll(ASTNode.copySubtrees(target, annotations())); + } + result.setName((Name) getName().clone(target)); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + if (this.ast.apiLevel >= AST.JLS3) { + acceptChild(visitor, getJavadoc()); + acceptChildren(visitor, this.annotations); + } + acceptChild(visitor, getName()); + } + visitor.endVisit(this); + } + + /** + * Returns the live ordered list of annotations of this + * package declaration (added in JLS3 API). + * + * @return the live list of annotations + * (element type: <code>Annotation</code>) + * @exception UnsupportedOperationException if this operation is used in + * a JLS2 AST + * @since 3.1 + */ + public List annotations() { + // more efficient than just calling unsupportedIn2() to check + if (this.annotations == null) { + unsupportedIn2(); + } + return this.annotations; + } + + /** + * Returns the doc comment node. + * + * @return the doc comment node, or <code>null</code> if none + * @exception UnsupportedOperationException if this operation is used in + * a JLS2 AST + * @since 3.0 + */ + public Javadoc getJavadoc() { + // more efficient than just calling unsupportedIn2() to check + if (this.annotations == null) { + unsupportedIn2(); + } + return this.optionalDocComment; + } + + /** + * Sets or clears the doc comment node. + * + * @param docComment the doc comment node, or <code>null</code> if none + * @exception IllegalArgumentException if the doc comment string is invalid + * @exception UnsupportedOperationException if this operation is used in + * a JLS2 AST + * @since 3.0 + */ + public void setJavadoc(Javadoc docComment) { + // more efficient than just calling unsupportedIn2() to check + if (this.annotations == null) { + unsupportedIn2(); + } + ASTNode oldChild = this.optionalDocComment; + preReplaceChild(oldChild, docComment, JAVADOC_PROPERTY); + this.optionalDocComment = docComment; + postReplaceChild(oldChild, docComment, JAVADOC_PROPERTY); + } + + /** + * Returns the package name of this package declaration. + * + * @return the package name node + */ + public Name getName() { + if (this.packageName == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.packageName == null) { + preLazyInit(); + this.packageName = new SimpleName(this.ast); + postLazyInit(this.packageName, NAME_PROPERTY); + } + } + } + return this.packageName; + } + + /** + * Sets the package name of this package declaration to the given name. + * + * @param name the new package name + * @exception IllegalArgumentException if`: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public void setName(Name name) { + if (name == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.packageName; + preReplaceChild(oldChild, name, NAME_PROPERTY); + this.packageName = name; + postReplaceChild(oldChild, name, NAME_PROPERTY); + } + + /** + * Resolves and returns the binding for the package declared in this package + * declaration. + * <p> + * Note that bindings are generally unavailable unless requested when the + * AST is being built. + * </p> + * + * @return the binding, or <code>null</code> if the binding cannot be + * resolved + */ + public IPackageBinding resolveBinding() { + return this.ast.getBindingResolver().resolvePackage(this); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return BASE_NODE_SIZE + 3 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.optionalDocComment == null ? 0 : getJavadoc().treeSize()) + + (this.annotations == null ? 0 : this.annotations.listSize()) + + (this.packageName == null ? 0 : getName().treeSize()); + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ParameterMapping.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ParameterMapping.java new file mode 100644 index 000000000..4e0157798 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ParameterMapping.java @@ -0,0 +1,385 @@ +/********************************************************************** + * This file is part of "Object Teams Development Tooling"-Software + * + * Copyright 2004, 2006 Fraunhofer Gesellschaft, Munich, Germany, + * for its Fraunhofer Institute for Computer Architecture and Software + * Technology (FIRST), Berlin, Germany and Technical University Berlin, + * Germany. + * + * 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 + * $Id: ParameterMapping.java 23416 2010-02-03 19:59:31Z stephan $ + * + * Please visit http://www.eclipse.org/objectteams for updates and contact. + * + * Contributors: + * Fraunhofer FIRST - Initial API and implementation + * Technical University Berlin - Initial API and implementation + **********************************************************************/ +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * NEW for OTDT. + * + * Represents the DOM-ASTNode for parameterMapping, which has to handle mappings for callin (OTJLD §4.4) and callout (OTJLD §3.2) bindings. + * + * Possible parameter mappings are: + * "integer.intValue() -> i" or "result <- new Integer(result)" for callout Bindings or + * "what <- uid" or "new Integer(i) -> result" for callin Bindings + * + * Contained AST elements: + * This class consists of one expression, one identifier, one direction and a flag, whether it is + * a return-parameter mapping or not. The direction is necessary for determination of callout and callin. + * + * Locations in source code: + * This node is used in CalloutMappingDeclartion, CallinMappingDeclaration + * + * @author ike + */ +public class ParameterMapping extends Expression +{ + /** + * Creates a new AST node for a ParameterMapping declaration owned + * by the given AST. By default, the declaration is for a ParameterMapping + * of an unspecified, but legal, name; + * <p> + * N.B. This constructor is package-private; all subclasses must be + * declared in the same package; clients are unable to declare + * additional subclasses. + * </p> + * + * @param ast the AST that is to own this node + */ + ParameterMapping(AST ast) + { + super(ast); + } + + + /** + * The expression structural property of this node type. + */ + public static final ChildPropertyDescriptor EXPRESSION_PROPERTY = + new ChildPropertyDescriptor(ParameterMapping.class, "expression", Expression.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The identifier structural property of this node type. + */ + public static final ChildPropertyDescriptor IDENTIFIER_PROPERTY = + new ChildPropertyDescriptor(ParameterMapping.class, "identifier", SimpleName.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The direction structural property of this node type. + */ + public static final SimplePropertyDescriptor DIRECTION_PROPERTY = + new SimplePropertyDescriptor(ParameterMapping.class, "direction", String.class, MANDATORY); //$NON-NLS-1$ + + /** + * The is_Result structural property of this node type. + */ + private static final SimplePropertyDescriptor IS_RESULT_PROPERTY = + new SimplePropertyDescriptor(ParameterMapping.class, "isResult", boolean.class, MANDATORY); //$NON-NLS-1$ + + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS_2_0; + + private Expression _expression = null; + private SimpleName _identifier = null; + private String _direction = null; + private boolean _isResult = false; + + static + { + List propertyList = new ArrayList(5); + createPropertyList(ParameterMapping.class, propertyList); + addProperty(EXPRESSION_PROPERTY, propertyList); + addProperty(IDENTIFIER_PROPERTY, propertyList); + addProperty(DIRECTION_PROPERTY, propertyList); + addProperty(IS_RESULT_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS_2_0 = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the AST.JLS* constants + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + */ + public static List propertyDescriptors(int apiLevel) + { + return PROPERTY_DESCRIPTORS_2_0; + } + + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the AST.JLS* constants + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + */ + List internalStructuralPropertiesForType(int apiLevel) + { + return PROPERTY_DESCRIPTORS_2_0; + } + + final ASTNode internalGetSetChildProperty( + ChildPropertyDescriptor property, + boolean isGet, + ASTNode child) + { + if (property == IDENTIFIER_PROPERTY) + { + if (isGet) + { + return getIdentifier(); + } + else + { + setIdentifier((SimpleName) child); + return null; + } + } + else if (property == EXPRESSION_PROPERTY) + { + if (isGet) + { + return getExpression(); + } + else + { + setExpression((Expression) child); + return null; + } + } + + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, isGet, child); + } + + final boolean internalGetSetBooleanProperty( + SimplePropertyDescriptor property, + boolean isGet, + boolean value) + { + if (property == IS_RESULT_PROPERTY) + { + if (isGet) + { + return hasResultFlag(); + } + else + { + setResultFlag(value); + return false; + } + } + return super.internalGetSetBooleanProperty(property, isGet, value); + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTNode#internalGetSetObjectProperty(org.eclipse.jdt.core.dom.SimplePropertyDescriptor, boolean, java.lang.Object) + */ + final Object internalGetSetObjectProperty( + SimplePropertyDescriptor property, + boolean isGet, + Object value) + { + + if (property == DIRECTION_PROPERTY) + { + if (isGet) + { + return getDirection(); + } + else + { + setDirection((String) value); + return null; + } + } + return super.internalGetSetObjectProperty(property, isGet, value); + } + + public boolean hasResultFlag() + { + return _isResult; + } + + public void setResultFlag(boolean resultFlag) + { + preValueChange(IS_RESULT_PROPERTY); + _isResult = resultFlag; + postValueChange(IS_RESULT_PROPERTY); + } + + public SimpleName getIdentifier() + { + if (_identifier == null) + { + // lazy init must be thread-safe for readers + synchronized (this) + { + if (_identifier == null) + { + preLazyInit(); + _identifier = new SimpleName(super.ast); + postLazyInit(_identifier, IDENTIFIER_PROPERTY); + } + } + } return _identifier; + } + + public void setIdentifier(SimpleName identifier) + { + if (identifier == null) + { + throw new IllegalArgumentException(); + } + ASTNode oldChild = _identifier; + preReplaceChild(oldChild, identifier, IDENTIFIER_PROPERTY); + _identifier = identifier; + postReplaceChild(oldChild, identifier, IDENTIFIER_PROPERTY); + } + + public String getDirection() + { + if (_direction == null) + { + // lazy init must be thread-safe for readers + synchronized (this) + { + if (_direction == null) + { + _direction = new String(""); //$NON-NLS-1$ + } + } + } + return _direction; + } + + public boolean isBindIN() { + return "<-".equals(getDirection()); + } + + public void setDirection(String direction) + { + if (direction == null) + { + throw new IllegalArgumentException(); + } + _direction = direction; + } + + + public ASTNode getExpression() + { + if (_expression == null) + { + // lazy init must be thread-safe for readers + synchronized (this) + { + if (_expression == null) + { + preLazyInit(); + _expression = new SimpleName(super.ast); + postLazyInit(_expression, EXPRESSION_PROPERTY); + } + } + } return _expression; + } + + public void setExpression(Expression expression) + { + if (expression == null) + { + throw new IllegalArgumentException(); + } + ASTNode oldChild = _expression; + preReplaceChild(oldChild, expression, EXPRESSION_PROPERTY); + _expression = expression; + postReplaceChild(oldChild, expression, EXPRESSION_PROPERTY); + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTNode#getNodeType0() + */ + int getNodeType0() + { + return ASTNode.PARAMETER_MAPPING; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTNode#subtreeMatch0(org.eclipse.jdt.core.dom.ASTMatcher, java.lang.Object) + */ + boolean subtreeMatch0(ASTMatcher matcher, Object other) + { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTNode#clone0(org.eclipse.jdt.core.dom.AST) + */ + ASTNode clone0(AST target) + { + ParameterMapping result = new ParameterMapping(target); + result.setSourceRange(this.getStartPosition(), this.getLength()); + result.setExpression((Expression) ASTNode.copySubtree(target,getExpression())); + result.setIdentifier((SimpleName) ASTNode.copySubtree(target,getIdentifier())); + result.setDirection(this.getDirection()); + result.setResultFlag(this.hasResultFlag()); + + return result; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTNode#accept0(org.eclipse.jdt.core.dom.ASTVisitor) + */ + void accept0(ASTVisitor visitor) + { + boolean visitChildren = visitor.visit(this); + if (visitChildren) + { + // visit children in normal left to right reading order + if (getDirection().equals("->")) { // expr -> id + acceptChild(visitor, getExpression()); + acceptChild(visitor, getIdentifier()); + } else { // id <- expr + acceptChild(visitor, getIdentifier()); + acceptChild(visitor, getExpression()); + } + } + visitor.endVisit(this); + + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTNode#treeSize() + */ + int treeSize() + { + return memSize() + getExpression().treeSize(); + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTNode#memSize() + */ + int memSize() + { + return BASE_NODE_SIZE + 4 * 4; + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ParameterizedType.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ParameterizedType.java new file mode 100644 index 000000000..1d108ce31 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ParameterizedType.java @@ -0,0 +1,273 @@ +/******************************************************************************* + * Copyright (c) 2003, 2008 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: + * IBM Corporation - initial API and implementation + * Technical University Berlin - extended API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Type node for a parameterized type (added in JLS3 API). + * These nodes are used for type references (as opposed to + * declarations of parameterized types.) + * <pre> + * ParameterizedType: + * Type <b><</b> Type { <b>,</b> Type } <b>></b> + * </pre> + * The first type may be a simple type or a qualified type; + * other kinds of types are meaningless. + * + * @since 3.1 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class ParameterizedType extends Type { + /** + * This index represents the position inside a parameterized qualified type. + */ + int index; + + /** + * The "type" structural property of this node type. + */ + public static final ChildPropertyDescriptor TYPE_PROPERTY = + new ChildPropertyDescriptor(ParameterizedType.class, "type", Type.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "typeArguments" structural property of this node type. + */ + public static final ChildListPropertyDescriptor TYPE_ARGUMENTS_PROPERTY = + new ChildListPropertyDescriptor(ParameterizedType.class, "typeArguments", Type.class, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List propertyList = new ArrayList(3); + createPropertyList(ParameterizedType.class, propertyList); + addProperty(TYPE_PROPERTY, propertyList); + addProperty(TYPE_ARGUMENTS_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The type node; lazily initialized; defaults to an unspecfied, but legal, + * type. + */ + private Type type = null; + + /** + * The type arguments (element type: <code>Type</code>). + * Defaults to an empty list. + */ + private ASTNode.NodeList typeArguments = + new ASTNode.NodeList(TYPE_ARGUMENTS_PROPERTY); + + /** + * Creates a new unparented node for a parameterized type owned by the + * given AST. By default, an unspecified, but legal, type, and no type + * arguments. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + ParameterizedType(AST ast) { + super(ast); + unsupportedIn2(); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == TYPE_PROPERTY) { + if (get) { + return getType(); + } else { + setType((Type) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalGetChildListProperty(ChildListPropertyDescriptor property) { + if (property == TYPE_ARGUMENTS_PROPERTY) { + return typeArguments(); + } + // allow default implementation to flag the error + return super.internalGetChildListProperty(property); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return PARAMETERIZED_TYPE; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + ParameterizedType result = new ParameterizedType(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setType((Type) ((ASTNode) getType()).clone(target)); + result.typeArguments().addAll( + ASTNode.copySubtrees(target, typeArguments())); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + acceptChild(visitor, getType()); + acceptChildren(visitor, this.typeArguments); + } + visitor.endVisit(this); + } + + /** + * Returns the type of this parameterized type. + * + * @return the type of this parameterized type + */ + public Type getType() { + if (this.type == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.type == null) { + preLazyInit(); + this.type = new SimpleType(this.ast); + postLazyInit(this.type, TYPE_PROPERTY); + } + } + } + return this.type; + } + + /** + * Sets the type of this parameterized type. + * + * @param type the new type of this parameterized type + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public void setType(Type type) { + if (type == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.type; + preReplaceChild(oldChild, type, TYPE_PROPERTY); + this.type = type; + postReplaceChild(oldChild, type, TYPE_PROPERTY); + } + + /** + * Returns the live ordered list of type arguments of this parameterized + * type. For the parameterized type to be plausible, the list should contain + * at least one element and not contain primitive types. + * + * @return the live list of type arguments + * (element type: <code>Type</code>) + */ + public List typeArguments() { + return this.typeArguments; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + // treat Code as free + return BASE_NODE_SIZE + 3 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.type == null ? 0 : getType().treeSize()) + + this.typeArguments.listSize(); + } + +//{ObjectTeams: value dependent type? + public boolean isDependentType(boolean onlyRelevant) { + if (this.typeArguments.listSize() == 0) + return false; + ASTNode arg0 = (ASTNode)this.typeArguments.get(0); + if (arg0.getNodeType() == ASTNode.TYPE_ANCHOR) { + Name path= ((TypeAnchor)arg0).getPath(); + if (path.isSimpleName()) + return ((SimpleName)path).getIdentifier().equals("tthis"); //$NON-NLS-1$ + } + return false; + } + public String[] getAnchorPath() { + if (this.typeArguments.listSize() > 0) { + Type type = (Type)this.typeArguments.get(0); + if (type.getNodeType() == ASTNode.TYPE_ANCHOR) + return ((TypeAnchor)type).getPath().getFullyQualifiedName().split("."); //$NON-NLS-1$ + } + return new String[0]; + } +// SH} + +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ParenthesizedExpression.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ParenthesizedExpression.java new file mode 100644 index 000000000..8be31ffe7 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ParenthesizedExpression.java @@ -0,0 +1,200 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Parenthesized expression AST node type. + * + * <pre> + * ParenthesizedExpression: + * <b>(</b> Expression <b>)</b> + * </pre> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class ParenthesizedExpression extends Expression { + + /** + * The "expression" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor EXPRESSION_PROPERTY = + new ChildPropertyDescriptor(ParenthesizedExpression.class, "expression", Expression.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List propertyList = new ArrayList(2); + createPropertyList(ParenthesizedExpression.class, propertyList); + addProperty(EXPRESSION_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The expression; lazily initialized; defaults to a unspecified, but legal, + * expression. + */ + private Expression expression = null; + + /** + * Creates a new unparented parenthesized expression node owned by the given + * AST. By default, the parenthesized expression has an unspecified, but + * legal, expression. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + ParenthesizedExpression(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == EXPRESSION_PROPERTY) { + if (get) { + return getExpression(); + } else { + setExpression((Expression) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return PARENTHESIZED_EXPRESSION; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + ParenthesizedExpression result = new ParenthesizedExpression(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setExpression((Expression) getExpression().clone(target)); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + acceptChild(visitor, getExpression()); + } + visitor.endVisit(this); + } + + /** + * Returns the expression of this parenthesized expression. + * + * @return the expression node + */ + public Expression getExpression() { + if (this.expression == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.expression == null) { + preLazyInit(); + this.expression = new SimpleName(this.ast); + postLazyInit(this.expression, EXPRESSION_PROPERTY); + } + } + } + return this.expression; + } + + /** + * Sets the expression of this parenthesized expression. + * + * @param expression the new expression node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setExpression(Expression expression) { + if (expression == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.expression; + preReplaceChild(oldChild, expression, EXPRESSION_PROPERTY); + this.expression = expression; + postReplaceChild(oldChild, expression, EXPRESSION_PROPERTY); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return BASE_NODE_SIZE + 1 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.expression == null ? 0 : getExpression().treeSize()); + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/PostfixExpression.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/PostfixExpression.java new file mode 100644 index 000000000..a51db30d8 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/PostfixExpression.java @@ -0,0 +1,330 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Postfix expression AST node type. + * + * <pre> + * PostfixExpression: + * Expression PostfixOperator + * </pre> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class PostfixExpression extends Expression { + + /** + * Postfix operators (typesafe enumeration). + * <pre> + * PostfixOperator: + * <b><code>++</code></b> <code>INCREMENT</code> + * <b><code>--</code></b> <code>DECREMENT</code> + * </pre> + */ + public static class Operator { + + /** + * The token for the operator. + */ + private String token; + + /** + * Creates a new postfix operator with the given token. + * <p> + * Note: this constructor is private. The only instances + * ever created are the ones for the standard operators. + * </p> + * + * @param token the character sequence for the operator + */ + private Operator(String token) { + this.token = token; + } + + /** + * Returns the character sequence for the operator. + * + * @return the character sequence for the operator + */ + public String toString() { + return this.token; + } + + /** Postfix increment "++" operator. */ + public static final Operator INCREMENT = new Operator("++");//$NON-NLS-1$ + /** Postfix decrement "--" operator. */ + public static final Operator DECREMENT = new Operator("--");//$NON-NLS-1$ + + /** + * Map from token to operator (key type: <code>String</code>; + * value type: <code>Operator</code>). + */ + private static final Map CODES; + static { + CODES = new HashMap(20); + Operator[] ops = { + INCREMENT, + DECREMENT, + }; + for (int i = 0; i < ops.length; i++) { + CODES.put(ops[i].toString(), ops[i]); + } + } + + /** + * Returns the postfix operator corresponding to the given string, + * or <code>null</code> if none. + * <p> + * <code>toOperator</code> is the converse of <code>toString</code>: + * that is, <code>Operator.toOperator(op.toString()) == op</code> for + * all operators <code>op</code>. + * </p> + * + * @param token the character sequence for the operator + * @return the postfix operator, or <code>null</code> if none + */ + public static Operator toOperator(String token) { + return (Operator) CODES.get(token); + } + } + + /** + * The "operator" structural property of this node type. + * @since 3.0 + */ + public static final SimplePropertyDescriptor OPERATOR_PROPERTY = + new SimplePropertyDescriptor(PostfixExpression.class, "operator", PostfixExpression.Operator.class, MANDATORY); //$NON-NLS-1$ + + /** + * The "operand" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor OPERAND_PROPERTY = + new ChildPropertyDescriptor(PostfixExpression.class, "operand", Expression.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List propertyList = new ArrayList(3); + createPropertyList(PostfixExpression.class, propertyList); + addProperty(OPERAND_PROPERTY, propertyList); + addProperty(OPERATOR_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The operator; defaults to an unspecified postfix operator. + */ + private PostfixExpression.Operator operator = + PostfixExpression.Operator.INCREMENT; + + /** + * The operand; lazily initialized; defaults to an unspecified, + * but legal, simple name. + */ + private Expression operand = null; + + /** + * Creates a new AST node for an postfix expression owned by the given + * AST. By default, the node has unspecified (but legal) operator and + * operand. + * + * @param ast the AST that is to own this node + */ + PostfixExpression(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final Object internalGetSetObjectProperty(SimplePropertyDescriptor property, boolean get, Object value) { + if (property == OPERATOR_PROPERTY) { + if (get) { + return getOperator(); + } else { + setOperator((Operator) value); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetObjectProperty(property, get, value); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == OPERAND_PROPERTY) { + if (get) { + return getOperand(); + } else { + setOperand((Expression) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return POSTFIX_EXPRESSION; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + PostfixExpression result = new PostfixExpression(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setOperator(getOperator()); + result.setOperand((Expression) getOperand().clone(target)); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + acceptChild(visitor, getOperand()); + } + visitor.endVisit(this); + } + + /** + * Returns the operator of this postfix expression. + * + * @return the operator + */ + public PostfixExpression.Operator getOperator() { + return this.operator; + } + + /** + * Sets the operator of this postfix expression. + * + * @param operator the operator + * @exception IllegalArgumentException if the argument is incorrect + */ + public void setOperator(PostfixExpression.Operator operator) { + if (operator == null) { + throw new IllegalArgumentException(); + } + preValueChange(OPERATOR_PROPERTY); + this.operator = operator; + postValueChange(OPERATOR_PROPERTY); + } + + /** + * Returns the operand of this postfix expression. + * + * @return the operand expression node + */ + public Expression getOperand() { + if (this.operand == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.operand == null) { + preLazyInit(); + this.operand= new SimpleName(this.ast); + postLazyInit(this.operand, OPERAND_PROPERTY); + } + } + } + return this.operand; + } + + /** + * Sets the operand of this postfix expression. + * + * @param expression the operand expression node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setOperand(Expression expression) { + if (expression == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.operand; + preReplaceChild(oldChild, expression, OPERAND_PROPERTY); + this.operand = expression; + postReplaceChild(oldChild, expression, OPERAND_PROPERTY); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + // treat Operator as free + return BASE_NODE_SIZE + 2 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.operand == null ? 0 : getOperand().treeSize()); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/PrecedenceDeclaration.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/PrecedenceDeclaration.java new file mode 100644 index 000000000..a5b868e71 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/PrecedenceDeclaration.java @@ -0,0 +1,128 @@ +/********************************************************************** + * This file is part of "Object Teams Development Tooling"-Software + * + * Copyright 2006 Fraunhofer Gesellschaft, Munich, Germany, + * for its Fraunhofer Institute for Computer Architecture and Software + * Technology (FIRST), Berlin, Germany and Technical University Berlin, + * Germany. + * + * 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 + * $Id: PrecedenceDeclaration.java 23417 2010-02-03 20:13:55Z stephan $ + * + * Please visit http://www.eclipse.org/objectteams for updates and contact. + * + * Contributors: + * Fraunhofer FIRST - Initial API and implementation + * Technical University Berlin - Initial API and implementation + **********************************************************************/ +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * This class represents a precedence declaration in OT/J (OTJLD §4.8). + * A precedence declaration contains a list of names + * referring either to classes or to callin bindings. + * + * @author stephan + */ +public class PrecedenceDeclaration extends ASTNode { + + @SuppressWarnings("nls") + public static final ChildListPropertyDescriptor ELEMENTS_PROPERTY = + new ChildListPropertyDescriptor(PrecedenceDeclaration.class, "elements", Name.class, NO_CYCLE_RISK); + + private static final List PROPERTY_DESCRIPTORS_3_0; + + static { + List propertyList = new ArrayList(2); + createPropertyList(PrecedenceDeclaration.class, propertyList); + addProperty(ELEMENTS_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS_3_0 = reapPropertyList(propertyList); + } + + public static List propertyDescriptors(int apiLevel) { + if (apiLevel == AST.JLS2_INTERNAL) { + throw new UnsupportedOperationException("JLS2 not supported"); //$NON-NLS-1$ + } else { + return PROPERTY_DESCRIPTORS_3_0; + } + } + + ASTNode.NodeList _elements = new ASTNode.NodeList(ELEMENTS_PROPERTY); + + PrecedenceDeclaration(AST ast) + { + super(ast); + } + + List internalGetChildListProperty(ChildListPropertyDescriptor property) + { + if (property == ELEMENTS_PROPERTY) { + return this._elements; + } + // allow default implementation to flag the error + return super.internalGetChildListProperty(property); + } + + @Override + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + if (this.ast.apiLevel == AST.JLS2_INTERNAL) { + unsupportedIn2(); + } + if (this.ast.apiLevel >= AST.JLS3) { + acceptChildren(visitor, this._elements); + } + } + visitor.endVisit(this); + } + + @Override + boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + @SuppressWarnings("unchecked") + @Override + ASTNode clone0(AST target) { + if (this.ast.apiLevel == AST.JLS2_INTERNAL) + unsupportedIn2(); + PrecedenceDeclaration result = new PrecedenceDeclaration(target); + result.setSourceRange(this.getStartPosition(), this.getLength()); + result.elements().addAll(ASTNode.copySubtrees(target, elements())); + return result; + } + + @Override + int getNodeType0() { + return PRECEDENCE_DECLARATION; + } + + @Override + List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + public List elements() { + return this._elements; + } + + @Override + int memSize() { + return BASE_NODE_SIZE; + } + + @Override + int treeSize() { + return memSize() + this._elements.listSize(); + } + +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/PrefixExpression.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/PrefixExpression.java new file mode 100644 index 000000000..196c800ba --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/PrefixExpression.java @@ -0,0 +1,348 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Prefix expression AST node type. + * + * <pre> + * PrefixExpression: + * PrefixOperator Expression + * </pre> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class PrefixExpression extends Expression { + + /** + * Prefix operators (typesafe enumeration). + * <pre> + * PrefixOperator: + * <b><code>++</code></b> <code>INCREMENT</code> + * <b><code>--</code></b> <code>DECREMENT</code> + * <b><code>+</code></b> <code>PLUS</code> + * <b><code>-</code></b> <code>MINUS</code> + * <b><code>~</code></b> <code>COMPLEMENT</code> + * <b><code>!</code></b> <code>NOT</code> + * </pre> + */ + public static class Operator { + + /** + * The token for the operator. + */ + private String token; + + /** + * Creates a new prefix operator with the given token. + * <p> + * Note: this constructor is private. The only instances + * ever created are the ones for the standard operators. + * </p> + * + * @param token the character sequence for the operator + */ + private Operator(String token) { + this.token = token; + } + + /** + * Returns the character sequence for the operator. + * + * @return the character sequence for the operator + */ + public String toString() { + return this.token; + } + + /** Prefix increment "++" operator. */ + public static final Operator INCREMENT = new Operator("++");//$NON-NLS-1$ + /** Prefix decrement "--" operator. */ + public static final Operator DECREMENT = new Operator("--");//$NON-NLS-1$ + /** Unary plus "+" operator. */ + public static final Operator PLUS = new Operator("+");//$NON-NLS-1$ + /** Unary minus "-" operator. */ + public static final Operator MINUS = new Operator("-");//$NON-NLS-1$ + /** Bitwise complement "~" operator. */ + public static final Operator COMPLEMENT = new Operator("~");//$NON-NLS-1$ + /** Logical complement "!" operator. */ + public static final Operator NOT = new Operator("!");//$NON-NLS-1$ + + /** + * Map from token to operator (key type: <code>String</code>; + * value type: <code>Operator</code>). + */ + private static final Map CODES; + static { + CODES = new HashMap(20); + Operator[] ops = { + INCREMENT, + DECREMENT, + PLUS, + MINUS, + COMPLEMENT, + NOT, + }; + for (int i = 0; i < ops.length; i++) { + CODES.put(ops[i].toString(), ops[i]); + } + } + + /** + * Returns the prefix operator corresponding to the given string, + * or <code>null</code> if none. + * <p> + * <code>toOperator</code> is the converse of <code>toString</code>: + * that is, <code>Operator.toOperator(op.toString()) == op</code> for + * all operators <code>op</code>. + * </p> + * + * @param token the character sequence for the operator + * @return the prefix operator, or <code>null</code> if none + */ + public static Operator toOperator(String token) { + return (Operator) CODES.get(token); + } + } + + /** + * The "operator" structural property of this node type. + * @since 3.0 + */ + public static final SimplePropertyDescriptor OPERATOR_PROPERTY = + new SimplePropertyDescriptor(PrefixExpression.class, "operator", PrefixExpression.Operator.class, MANDATORY); //$NON-NLS-1$ + + /** + * The "operand" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor OPERAND_PROPERTY = + new ChildPropertyDescriptor(PrefixExpression.class, "operand", Expression.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List propertyList = new ArrayList(3); + createPropertyList(PrefixExpression.class, propertyList); + addProperty(OPERATOR_PROPERTY, propertyList); + addProperty(OPERAND_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The operator; defaults to an unspecified prefix operator. + */ + private PrefixExpression.Operator operator = + PrefixExpression.Operator.PLUS; + + /** + * The operand; lazily initialized; defaults to an unspecified, + * but legal, simple name. + */ + private Expression operand = null; + + /** + * Creates a new AST node for an prefix expression owned by the given + * AST. By default, the node has unspecified (but legal) operator and + * operand. + * + * @param ast the AST that is to own this node + */ + PrefixExpression(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final Object internalGetSetObjectProperty(SimplePropertyDescriptor property, boolean get, Object value) { + if (property == OPERATOR_PROPERTY) { + if (get) { + return getOperator(); + } else { + setOperator((Operator) value); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetObjectProperty(property, get, value); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == OPERAND_PROPERTY) { + if (get) { + return getOperand(); + } else { + setOperand((Expression) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return PREFIX_EXPRESSION; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + PrefixExpression result = new PrefixExpression(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setOperator(getOperator()); + result.setOperand((Expression) getOperand().clone(target)); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + acceptChild(visitor, getOperand()); + } + visitor.endVisit(this); + } + + /** + * Returns the operator of this prefix expression. + * + * @return the operator + */ + public PrefixExpression.Operator getOperator() { + return this.operator; + } + + /** + * Sets the operator of this prefix expression. + * + * @param operator the operator + * @exception IllegalArgumentException if the argument is incorrect + */ + public void setOperator(PrefixExpression.Operator operator) { + if (operator == null) { + throw new IllegalArgumentException(); + } + preValueChange(OPERATOR_PROPERTY); + this.operator = operator; + postValueChange(OPERATOR_PROPERTY); + } + + /** + * Returns the operand of this prefix expression. + * + * @return the operand expression node + */ + public Expression getOperand() { + if (this.operand == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.operand == null) { + preLazyInit(); + this.operand= new SimpleName(this.ast); + postLazyInit(this.operand, OPERAND_PROPERTY); + } + } + } + return this.operand; + } + + /** + * Sets the operand of this prefix expression. + * + * @param expression the operand expression node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setOperand(Expression expression) { + if (expression == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.operand; + preReplaceChild(oldChild, expression, OPERAND_PROPERTY); + this.operand = expression; + postReplaceChild(oldChild, expression, OPERAND_PROPERTY); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + // treat Operator as free + return BASE_NODE_SIZE + 2 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.operand == null ? 0 : getOperand().treeSize()); + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/PrimitiveType.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/PrimitiveType.java new file mode 100644 index 000000000..0dcf6fff1 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/PrimitiveType.java @@ -0,0 +1,302 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Primitive type nodes. + * <pre> + * PrimitiveType: + * <b>byte</b> + * <b>short</b> + * <b>char</b> + * <b>int</b> + * <b>long</b> + * <b>float</b> + * <b>double</b> + * <b>boolean</b> + * <b>void</b> + * </pre> + * <p> + * Note that due to the fact that AST nodes belong to a specific AST and + * have a specific parent, there needs to multiple instances of these + * nodes. + * </p> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class PrimitiveType extends Type { + + /** + * Primitive type codes (typesafe enumeration). + * <pre> + * <b>byte</b> BYTE + * <b>short</b> SHORT + * <b>char</b> CHAR + * <b>int</b> INT + * <b>long</b> LONG + * <b>float</b> FLOAT + * <b>double</b> DOUBLE + * <b>boolean</b> BOOLEAN + * <b>void</b> VOID + * </pre> + */ + public static class Code { + + /** + * The name of the type. + */ + private String name; + + /** + * Creates a new primitive type code with the given name. + * <p> + * Note: this constructor is package-private. The only instances + * ever created are the ones for the standard primitive types. + * </p> + * + * @param name the standard name of the primitive type + */ + Code(String name) { + this.name = name; + } + + /** + * Returns the standard name of the primitive type. + * + * @return the standard name of the primitive type + */ + public String toString() { + return this.name; + } + } + + /** Type code for the primitive type "int". */ + public static final Code INT = new Code("int");//$NON-NLS-1$ + /** Type code for the primitive type "char". */ + public static final Code CHAR = new Code("char");//$NON-NLS-1$ + /** Type code for the primitive type "boolean". */ + public static final Code BOOLEAN = new Code("boolean");//$NON-NLS-1$ + /** Type code for the primitive type "short". */ + public static final Code SHORT = new Code("short");//$NON-NLS-1$ + /** Type code for the primitive type "long". */ + public static final Code LONG = new Code("long");//$NON-NLS-1$ + /** Type code for the primitive type "float". */ + public static final Code FLOAT = new Code("float");//$NON-NLS-1$ + /** Type code for the primitive type "double". */ + public static final Code DOUBLE = new Code("double");//$NON-NLS-1$ + /** Type code for the primitive type "byte". */ + public static final Code BYTE = new Code("byte");//$NON-NLS-1$ + + /** Type code for the primitive type "void". Note that "void" is + * special in that its only legitimate uses are as a method return + * type and as a type literal. + */ + public static final Code VOID = new Code("void");//$NON-NLS-1$ + + /** + * The primitive type code; one of the PrimitiveType constants; default + * is int. + */ + private PrimitiveType.Code typeCode = INT; + + /** + * Map from token to primitive type code (key type: <code>String</code>; + * value type: <code>PrimitiveType.Code</code>). + */ + private static final Map CODES; + static { + CODES = new HashMap(20); + Code[] ops = { + INT, + BYTE, + CHAR, + BOOLEAN, + SHORT, + LONG, + FLOAT, + DOUBLE, + VOID, + }; + for (int i = 0; i < ops.length; i++) { + CODES.put(ops[i].toString(), ops[i]); + } + } + + /** + * Returns the primitive type code corresponding to the given string, + * or <code>null</code> if none. + * <p> + * <code>toCode</code> is the converse of <code>toString</code>: + * that is, + * <code>PrimitiveType.Code.toCode(code.toString()) == code</code> + * for all type code <code>code</code>. + * </p> + * + * @param token the standard name of the primitive type + * @return the primitive type code, or <code>null</code> if none + */ + public static PrimitiveType.Code toCode(String token) { + return (PrimitiveType.Code) CODES.get(token); + } + + /** + * The "primitiveTypeCode" structural property of this node type. + * @since 3.0 + */ + public static final SimplePropertyDescriptor PRIMITIVE_TYPE_CODE_PROPERTY = + new SimplePropertyDescriptor(PrimitiveType.class, "primitiveTypeCode", PrimitiveType.Code.class, MANDATORY); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List propertyList = new ArrayList(2); + createPropertyList(PrimitiveType.class, propertyList); + addProperty(PRIMITIVE_TYPE_CODE_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * Creates a new unparented node for a primitive type owned by the given + * AST. By default, the node has type "int". + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + PrimitiveType(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final Object internalGetSetObjectProperty(SimplePropertyDescriptor property, boolean get, Object value) { + if (property == PRIMITIVE_TYPE_CODE_PROPERTY) { + if (get) { + return getPrimitiveTypeCode(); + } else { + setPrimitiveTypeCode((Code) value); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetObjectProperty(property, get, value); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return PRIMITIVE_TYPE; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + PrimitiveType result = new PrimitiveType(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setPrimitiveTypeCode(getPrimitiveTypeCode()); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + visitor.visit(this); + visitor.endVisit(this); + } + + /** + * Returns the primitive type code. + * + * @return one of the primitive type code constants declared in this + * class + */ + public PrimitiveType.Code getPrimitiveTypeCode() { + return this.typeCode; + } + + /** + * Sets the primitive type code. + * + * @param typeCode one of the primitive type code constants declared in + * this class + * @exception IllegalArgumentException if the argument is incorrect + */ + public void setPrimitiveTypeCode(PrimitiveType.Code typeCode) { + if (typeCode == null) { + throw new IllegalArgumentException(); + } + preValueChange(PRIMITIVE_TYPE_CODE_PROPERTY); + this.typeCode = typeCode; + postValueChange(PRIMITIVE_TYPE_CODE_PROPERTY); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + // treat Code as free + return BASE_NODE_SIZE + 1 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return memSize(); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/QualifiedName.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/QualifiedName.java new file mode 100644 index 000000000..002c3604e --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/QualifiedName.java @@ -0,0 +1,281 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + + +/** + * AST node for a qualified name. A qualified name is defined recursively + * as a simple name preceded by a name, which qualifies it. Expressing it this + * way means that the qualifier and the simple name get their own AST nodes. + * <pre> + * QualifiedName: + * Name <b>.</b> SimpleName + * </pre> + * <p> + * See <code>FieldAccess</code> for guidelines on handling other expressions + * that resemble qualified names. + * </p> + * + * @see FieldAccess + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class QualifiedName extends Name { + + /** + * The "qualifier" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor QUALIFIER_PROPERTY = + new ChildPropertyDescriptor(QualifiedName.class, "qualifier", Name.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "name" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor NAME_PROPERTY = + new ChildPropertyDescriptor(QualifiedName.class, "name", SimpleName.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List propertyList = new ArrayList(3); + createPropertyList(QualifiedName.class, propertyList); + addProperty(QUALIFIER_PROPERTY, propertyList); + addProperty(NAME_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The identifier; lazily initialized; defaults to a unspecified, legal + * Java identifier. + */ + private Name qualifier = null; + + /** + * The name being qualified; lazily initialized; defaults to a unspecified, + * legal Java identifier. + */ + private SimpleName name = null; + + /** + * Creates a new AST node for a qualified name owned by the given AST. + * <p> + * N.B. This constructor is package-private; all subclasses must be + * declared in the same package; clients are unable to declare + * additional subclasses. + * </p> + * + * @param ast the AST that is to own this node + */ + QualifiedName(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == QUALIFIER_PROPERTY) { + if (get) { + return getQualifier(); + } else { + setQualifier((Name) child); + return null; + } + } + if (property == NAME_PROPERTY) { + if (get) { + return getName(); + } else { + setName((SimpleName) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return QUALIFIED_NAME; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + QualifiedName result = new QualifiedName(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setQualifier((Name) getQualifier().clone(target)); + result.setName((SimpleName) getName().clone(target)); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + acceptChild(visitor, getQualifier()); + acceptChild(visitor, getName()); + } + visitor.endVisit(this); + } + + /** + * Returns the qualifier part of this qualified name. + * + * @return the qualifier part of this qualified name + */ + public Name getQualifier() { + if (this.qualifier == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.qualifier == null) { + preLazyInit(); + this.qualifier = new SimpleName(this.ast); + postLazyInit(this.qualifier, QUALIFIER_PROPERTY); + } + } + } + return this.qualifier; + } + + /** + * Sets the qualifier of this qualified name to the given name. + * + * @param qualifier the qualifier of this qualified name + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setQualifier(Name qualifier) { + if (qualifier == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.qualifier; + preReplaceChild(oldChild, qualifier, QUALIFIER_PROPERTY); + this.qualifier = qualifier; + postReplaceChild(oldChild, qualifier, QUALIFIER_PROPERTY); + } + + /** + * Returns the name part of this qualified name. + * + * @return the name being qualified + */ + public SimpleName getName() { + if (this.name == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.name == null) { + preLazyInit(); + this.name = new SimpleName(this.ast); + postLazyInit(this.name, NAME_PROPERTY); + } + } + } + return this.name; + } + + /** + * Sets the name part of this qualified name to the given simple name. + * + * @param name the identifier of this qualified name + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public void setName(SimpleName name) { + if (name == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.name; + preReplaceChild(oldChild, name, NAME_PROPERTY); + this.name = name; + postReplaceChild(oldChild, name, NAME_PROPERTY); + } + + /* (omit javadoc for this method) + * Method declared on Name. + */ + void appendName(StringBuffer buffer) { + getQualifier().appendName(buffer); + buffer.append('.'); + getName().appendName(buffer); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return BASE_NAME_NODE_SIZE + 3 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.name == null ? 0 : getName().treeSize()) + + (this.qualifier == null ? 0 : getQualifier().treeSize()); + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/QualifiedType.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/QualifiedType.java new file mode 100644 index 000000000..5dc5edaa7 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/QualifiedType.java @@ -0,0 +1,285 @@ +/******************************************************************************* + * Copyright (c) 2003, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Type node for a qualified type (added in JLS3 API). + * <pre> + * QualifiedType: + * Type <b>.</b> SimpleName + * </pre> + * <p> + * Not all node arragements will represent legal Java constructs. In particular, + * it is nonsense if the type is an array type or primitive type. The normal use + * is when the type is a simple or parameterized type. + * </p> + * <p> + * A type like "A.B" can be represented either of two ways: + * <ol> + * <li> + * <code>QualifiedType(SimpleType(SimpleName("A")),SimpleName("B"))</code> + * </li> + * <li> + * <code>SimpleType(QualifiedName(SimpleName("A"),SimpleName("B")))</code> + * </li> + * </ol> + * The first form is preferred when "A" is known to be a type. However, a + * parser cannot always determine this. Clients should be prepared to handle + * either rather than make assumptions. (Note also that the first form + * became possible as of JLS3; only the second form existed in JLS2 API.) + * </p> + * + * @since 3.1 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class QualifiedType extends Type { + /** + * This index represents the position inside a parameterized qualified type. + */ + int index; + + /** + * The "qualifier" structural property of this node type. + */ + public static final ChildPropertyDescriptor QUALIFIER_PROPERTY = + new ChildPropertyDescriptor(QualifiedType.class, "qualifier", Type.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "name" structural property of this node type. + */ + public static final ChildPropertyDescriptor NAME_PROPERTY = + new ChildPropertyDescriptor(QualifiedType.class, "name", SimpleName.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List propertyList = new ArrayList(3); + createPropertyList(QualifiedType.class, propertyList); + addProperty(QUALIFIER_PROPERTY, propertyList); + addProperty(NAME_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The type node; lazily initialized; defaults to a type with + * an unspecfied, but legal, simple name. + */ + private Type qualifier = null; + + /** + * The name being qualified; lazily initialized; defaults to a unspecified, + * legal Java identifier. + */ + private SimpleName name = null; + + /** + * Creates a new unparented node for a qualified type owned by the + * given AST. By default, an unspecified, but legal, qualifier and name. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + QualifiedType(AST ast) { + super(ast); + unsupportedIn2(); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == QUALIFIER_PROPERTY) { + if (get) { + return getQualifier(); + } else { + setQualifier((Type) child); + return null; + } + } + if (property == NAME_PROPERTY) { + if (get) { + return getName(); + } else { + setName((SimpleName) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return QUALIFIED_TYPE; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + QualifiedType result = new QualifiedType(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setQualifier((Type) ((ASTNode) getQualifier()).clone(target)); + result.setName((SimpleName) ((ASTNode) getName()).clone(target)); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + acceptChild(visitor, getQualifier()); + acceptChild(visitor, getName()); + } + visitor.endVisit(this); + } + + /** + * Returns the qualifier of this qualified type. + * + * @return the qualifier of this qualified type + */ + public Type getQualifier() { + if (this.qualifier == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.qualifier == null) { + preLazyInit(); + this.qualifier = new SimpleType(this.ast); + postLazyInit(this.qualifier, QUALIFIER_PROPERTY); + } + } + } + return this.qualifier; + } + + /** + * Sets the qualifier of this qualified type to the given type. + * + * @param type the new qualifier of this qualified type + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public void setQualifier(Type type) { + if (type == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.qualifier; + preReplaceChild(oldChild, type, QUALIFIER_PROPERTY); + this.qualifier = type; + postReplaceChild(oldChild, type, QUALIFIER_PROPERTY); + } + + /** + * Returns the name part of this qualified type. + * + * @return the name being qualified + */ + public SimpleName getName() { + if (this.name == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.name == null) { + preLazyInit(); + this.name = new SimpleName(this.ast); + postLazyInit(this.name, NAME_PROPERTY); + } + } + } + return this.name; + } + + /** + * Sets the name part of this qualified type to the given simple name. + * + * @param name the identifier of this qualified name + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public void setName(SimpleName name) { + if (name == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.name; + preReplaceChild(oldChild, name, NAME_PROPERTY); + this.name = name; + postReplaceChild(oldChild, name, NAME_PROPERTY); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + // treat Code as free + return BASE_NODE_SIZE + 3 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.qualifier == null ? 0 : getQualifier().treeSize()) + + (this.name == null ? 0 : getName().treeSize()); + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/RecoveredTypeBinding.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/RecoveredTypeBinding.java new file mode 100644 index 000000000..3b40c3ed4 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/RecoveredTypeBinding.java @@ -0,0 +1,797 @@ +/******************************************************************************* + * Copyright (c) 2007, 2009 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: + * IBM Corporation - initial API and implementation + * Technical University Berlin - extended API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jdt.core.Flags; +import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding; +import org.eclipse.jdt.internal.compiler.lookup.Binding; +import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope; +import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; +import org.eclipse.jdt.internal.compiler.util.SuffixConstants; +import org.eclipse.jdt.internal.compiler.util.Util; +import org.eclipse.jdt.internal.core.PackageFragment; +import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.CallinCalloutBinding; +import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.DependentTypeBinding; +import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.RoleTypeBinding; + +/** + * <h4>OTDT changes:</h4> + * <dl> + * <dt>What:<dd> new lookup functions, some from ITypeBinding plus some additional ones. + * </dl> + * <hr> + * This class represents the recovered binding for a type + */ +class RecoveredTypeBinding implements ITypeBinding { + + private VariableDeclaration variableDeclaration; + private Type currentType; + private BindingResolver resolver; + private int dimensions; + private RecoveredTypeBinding innerTypeBinding; + private ITypeBinding[] typeArguments; + private org.eclipse.jdt.internal.compiler.lookup.TypeBinding binding; + + RecoveredTypeBinding(BindingResolver resolver, VariableDeclaration variableDeclaration) { + this.variableDeclaration = variableDeclaration; + this.resolver = resolver; + this.currentType = getType(); + this.dimensions = variableDeclaration.getExtraDimensions(); + if (this.currentType.isArrayType()) { + this.dimensions += ((ArrayType) this.currentType).getDimensions(); + } + } + + RecoveredTypeBinding(BindingResolver resolver, org.eclipse.jdt.internal.compiler.lookup.TypeBinding typeBinding) { + this.resolver = resolver; + this.dimensions = typeBinding.dimensions(); + this.binding = typeBinding; + } + + RecoveredTypeBinding(BindingResolver resolver, Type type) { + this.currentType = type; + this.resolver = resolver; + this.dimensions = 0; + if (type.isArrayType()) { + this.dimensions += ((ArrayType) type).getDimensions(); + } + } + + RecoveredTypeBinding(BindingResolver resolver, RecoveredTypeBinding typeBinding, int dimensions) { + this.innerTypeBinding = typeBinding; + this.dimensions = typeBinding.getDimensions() + dimensions; + this.resolver = resolver; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#createArrayType(int) + */ + public ITypeBinding createArrayType(int dims) { + return this.resolver.getTypeBinding(this, dims); + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#getBinaryName() + */ + public String getBinaryName() { + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#getBound() + */ + public ITypeBinding getBound() { + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#getGenericTypeOfWildcardType() + */ + public ITypeBinding getGenericTypeOfWildcardType() { + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#getRank() + */ + public int getRank() { + return -1; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#getComponentType() + */ + public ITypeBinding getComponentType() { + if (this.dimensions == 0) return null; + return this.resolver.getTypeBinding(this, -1); + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#getDeclaredFields() + */ + public IVariableBinding[] getDeclaredFields() { + return TypeBinding.NO_VARIABLE_BINDINGS; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#getDeclaredMethods() + */ + public IMethodBinding[] getDeclaredMethods() { + return TypeBinding.NO_METHOD_BINDINGS; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#getDeclaredModifiers() + */ + public int getDeclaredModifiers() { + return 0; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#getDeclaredTypes() + */ + public ITypeBinding[] getDeclaredTypes() { + return TypeBinding.NO_TYPE_BINDINGS; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#getDeclaringClass() + */ + public ITypeBinding getDeclaringClass() { + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#getDeclaringMethod() + */ + public IMethodBinding getDeclaringMethod() { + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#getDimensions() + */ + public int getDimensions() { + return this.dimensions; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#getElementType() + */ + public ITypeBinding getElementType() { + if (this.binding != null) { + if (this.binding.isArrayType()) { + ArrayBinding arrayBinding = (ArrayBinding) this.binding; + return new RecoveredTypeBinding(this.resolver, arrayBinding.leafComponentType); + } else { + return new RecoveredTypeBinding(this.resolver, this.binding); + } + } + if (this.innerTypeBinding != null) { + return this.innerTypeBinding.getElementType(); + } + if (this.currentType!= null && this.currentType.isArrayType()) { + return this.resolver.getTypeBinding(((ArrayType) this.currentType).getElementType()); + } + if (this.variableDeclaration != null && this.variableDeclaration.getExtraDimensions() != 0) { + return this.resolver.getTypeBinding(getType()); + } + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#getErasure() + */ + public ITypeBinding getErasure() { + return this; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#getInterfaces() + */ + public ITypeBinding[] getInterfaces() { + return TypeBinding.NO_TYPE_BINDINGS; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#getModifiers() + */ + public int getModifiers() { + return Modifier.NONE; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#getName() + */ + public String getName() { + char[] brackets = new char[this.dimensions * 2]; + for (int i = this.dimensions * 2 - 1; i >= 0; i -= 2) { + brackets[i] = ']'; + brackets[i - 1] = '['; + } + StringBuffer buffer = new StringBuffer(getInternalName()); + buffer.append(brackets); + return String.valueOf(buffer); + } + + private String getInternalName() { + if (this.innerTypeBinding != null) { + return this.innerTypeBinding.getInternalName(); + } + ReferenceBinding referenceBinding = getReferenceBinding(); + if (referenceBinding != null) { + return new String(referenceBinding.compoundName[referenceBinding.compoundName.length - 1]); + } + return getTypeNameFrom(getType()); + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#getPackage() + */ + public IPackageBinding getPackage() { + if (this.binding != null) { + switch (this.binding.kind()) { + case Binding.BASE_TYPE : + case Binding.ARRAY_TYPE : + case Binding.TYPE_PARAMETER : // includes capture scenario + case Binding.WILDCARD_TYPE : + case Binding.INTERSECTION_TYPE: + return null; + } + IPackageBinding packageBinding = this.resolver.getPackageBinding(this.binding.getPackage()); + if (packageBinding != null) return packageBinding; + } + if (this.innerTypeBinding != null && this.dimensions > 0) { + return null; + } + CompilationUnitScope scope = this.resolver.scope(); + if (scope != null) { + return this.resolver.getPackageBinding(scope.getCurrentPackage()); + } + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#getQualifiedName() + */ + public String getQualifiedName() { + ReferenceBinding referenceBinding = getReferenceBinding(); + if (referenceBinding != null) { + StringBuffer buffer = new StringBuffer(); + char[] brackets = new char[this.dimensions * 2]; + for (int i = this.dimensions * 2 - 1; i >= 0; i -= 2) { + brackets[i] = ']'; + brackets[i - 1] = '['; + } + buffer.append(CharOperation.toString(referenceBinding.compoundName)); + buffer.append(brackets); + return String.valueOf(buffer); + } else { + return getName(); + } + } + + private ReferenceBinding getReferenceBinding() { + if (this.binding != null) { + if (this.binding.isArrayType()) { + ArrayBinding arrayBinding = (ArrayBinding) this.binding; + if (arrayBinding.leafComponentType instanceof ReferenceBinding) { + return (ReferenceBinding) arrayBinding.leafComponentType; + } + } else if (this.binding instanceof ReferenceBinding) { + return (ReferenceBinding) this.binding; + } + } else if (this.innerTypeBinding != null) { + return this.innerTypeBinding.getReferenceBinding(); + } + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#getSuperclass() + */ + public ITypeBinding getSuperclass() { + if (getQualifiedName().equals("java.lang.Object")) { //$NON-NLS-1$ + return null; + } + return this.resolver.resolveWellKnownType("java.lang.Object"); //$NON-NLS-1$ + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#getTypeArguments() + */ + public ITypeBinding[] getTypeArguments() { + if (this.binding != null) { + return this.typeArguments = TypeBinding.NO_TYPE_BINDINGS; + } + if (this.typeArguments != null) { + return this.typeArguments; + } + + if (this.innerTypeBinding != null) { + return this.innerTypeBinding.getTypeArguments(); + } + + if (this.currentType.isParameterizedType()) { + ParameterizedType parameterizedType = (ParameterizedType) this.currentType; + List typeArgumentsList = parameterizedType.typeArguments(); + int size = typeArgumentsList.size(); + ITypeBinding[] temp = new ITypeBinding[size]; + for (int i = 0; i < size; i++) { + ITypeBinding currentTypeBinding = ((Type) typeArgumentsList.get(i)).resolveBinding(); + if (currentTypeBinding == null) { + return this.typeArguments = TypeBinding.NO_TYPE_BINDINGS; + } + temp[i] = currentTypeBinding; + } + return this.typeArguments = temp; + } + return this.typeArguments = TypeBinding.NO_TYPE_BINDINGS; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#getTypeBounds() + */ + public ITypeBinding[] getTypeBounds() { + return TypeBinding.NO_TYPE_BINDINGS; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#getTypeDeclaration() + */ + public ITypeBinding getTypeDeclaration() { + return this; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#getTypeParameters() + */ + public ITypeBinding[] getTypeParameters() { + return TypeBinding.NO_TYPE_BINDINGS; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#getWildcard() + */ + public ITypeBinding getWildcard() { + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#isAnnotation() + */ + public boolean isAnnotation() { + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#isAnonymous() + */ + public boolean isAnonymous() { + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#isArray() + */ + public boolean isArray() { + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#isAssignmentCompatible(org.eclipse.jdt.core.dom.ITypeBinding) + */ + public boolean isAssignmentCompatible(ITypeBinding typeBinding) { + if ("java.lang.Object".equals(typeBinding.getQualifiedName())) { //$NON-NLS-1$ + return true; + } + // since recovered binding are not unique isEqualTo is required + return isEqualTo(typeBinding); + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#isCapture() + */ + public boolean isCapture() { + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#isCastCompatible(org.eclipse.jdt.core.dom.ITypeBinding) + */ + public boolean isCastCompatible(ITypeBinding typeBinding) { + if ("java.lang.Object".equals(typeBinding.getQualifiedName())) { //$NON-NLS-1$ + return true; + } + // since recovered binding are not unique isEqualTo is required + return isEqualTo(typeBinding); + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#isClass() + */ + public boolean isClass() { + return true; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#isEnum() + */ + public boolean isEnum() { + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#isFromSource() + */ + public boolean isFromSource() { + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#isGenericType() + */ + public boolean isGenericType() { + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#isInterface() + */ + public boolean isInterface() { + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#isLocal() + */ + public boolean isLocal() { + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#isMember() + */ + public boolean isMember() { + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#isNested() + */ + public boolean isNested() { + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#isNullType() + */ + public boolean isNullType() { + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#isParameterizedType() + */ + public boolean isParameterizedType() { + if (this.innerTypeBinding != null) { + return this.innerTypeBinding.isParameterizedType(); + } + if (this.currentType != null) { + return this.currentType.isParameterizedType(); + } + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#isPrimitive() + */ + public boolean isPrimitive() { + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#isRawType() + */ + public boolean isRawType() { + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#isSubTypeCompatible(org.eclipse.jdt.core.dom.ITypeBinding) + */ + public boolean isSubTypeCompatible(ITypeBinding typeBinding) { + if ("java.lang.Object".equals(typeBinding.getQualifiedName())) { //$NON-NLS-1$ + return true; + } + // since recovered binding are not unique isEqualTo is required + return isEqualTo(typeBinding); + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#isTopLevel() + */ + public boolean isTopLevel() { + return true; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#isTypeVariable() + */ + public boolean isTypeVariable() { + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#isUpperbound() + */ + public boolean isUpperbound() { + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#isWildcardType() + */ + public boolean isWildcardType() { + return false; + } + +//{ObjectTeams: implement OT method from ITypeBinding: + public boolean isTeam() { + if (this.currentType != null) + return Flags.isTeam(this.currentType.getFlags()); + return false; + } + public boolean isRole() { + if (this.currentType != null) + return Flags.isRole(this.currentType.getFlags()); + return false; + } + public boolean isClassPartOf (ITypeBinding other) { + return false; + } + public boolean isSynthRoleIfc() { + return false; + } + public ITypeBinding getIfcPart() { + if (isInterface()) + return this; + return null; + } + public ITypeBinding getBaseClass() { + return null; + } + public ITypeBinding[] getSuperRoles() { + return TypeBinding.NO_TYPE_BINDINGS; + } + public String getOptimalName() { + return this.getQualifiedName(); + } +// SH} + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.IBinding#getAnnotations() + */ + public IAnnotationBinding[] getAnnotations() { + return AnnotationBinding.NoAnnotations; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.IBinding#getJavaElement() + */ + public IJavaElement getJavaElement() { + IPackageBinding packageBinding = getPackage(); + if (packageBinding != null) { + final IJavaElement javaElement = packageBinding.getJavaElement(); + if (javaElement != null && javaElement.getElementType() == IJavaElement.PACKAGE_FRAGMENT) { + // best effort: we don't know if the recovered binding is a binary or source binding, so go with a compilation unit + return ((PackageFragment) javaElement).getCompilationUnit(getInternalName() + SuffixConstants.SUFFIX_STRING_java); + } + } + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.IBinding#getKey() + */ + public String getKey() { + StringBuffer buffer = new StringBuffer(); + buffer.append("Recovered#"); //$NON-NLS-1$ + if (this.innerTypeBinding != null) { + buffer.append("innerTypeBinding") //$NON-NLS-1$ + .append(this.innerTypeBinding.getKey()); + } else if (this.currentType != null) { + buffer.append("currentType") //$NON-NLS-1$ + .append(this.currentType.toString()); + } else if (this.binding != null) { + buffer.append("typeBinding") //$NON-NLS-1$ + .append(this.binding.computeUniqueKey()); + } else if (this.variableDeclaration != null) { + buffer + .append("variableDeclaration") //$NON-NLS-1$ + .append(this.variableDeclaration.getClass()) + .append(this.variableDeclaration.getName().getIdentifier()) + .append(this.variableDeclaration.getExtraDimensions()); + } + buffer.append(getDimensions()); + if (this.typeArguments != null) { + buffer.append('<'); + for (int i = 0, max = this.typeArguments.length; i < max; i++) { + if (i != 0) { + buffer.append(','); + } + buffer.append(this.typeArguments[i].getKey()); + } + buffer.append('>'); + } + return String.valueOf(buffer); + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.IBinding#getKind() + */ + public int getKind() { + return IBinding.TYPE; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.IBinding#isDeprecated() + */ + public boolean isDeprecated() { + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.IBinding#isEqualTo(org.eclipse.jdt.core.dom.IBinding) + */ + public boolean isEqualTo(IBinding other) { + if (!other.isRecovered() || other.getKind() != IBinding.TYPE) return false; + return getKey().equals(other.getKey()); + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.IBinding#isRecovered() + */ + public boolean isRecovered() { + return true; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.IBinding#isSynthetic() + */ + public boolean isSynthetic() { + return false; + } + + private String getTypeNameFrom(Type type) { + if (type == null) return Util.EMPTY_STRING; + switch(type.getNodeType0()) { + case ASTNode.ARRAY_TYPE : + ArrayType arrayType = (ArrayType) type; + type = arrayType.getElementType(); + return getTypeNameFrom(type); + case ASTNode.PARAMETERIZED_TYPE : + ParameterizedType parameterizedType = (ParameterizedType) type; + StringBuffer buffer = new StringBuffer(getTypeNameFrom(parameterizedType.getType())); + ITypeBinding[] tArguments = getTypeArguments(); + final int typeArgumentsLength = tArguments.length; + if (typeArgumentsLength != 0) { + buffer.append('<'); + for (int i = 0; i < typeArgumentsLength; i++) { + if (i > 0) { + buffer.append(','); + } + buffer.append(tArguments[i].getName()); + } + buffer.append('>'); + } + return String.valueOf(buffer); + case ASTNode.PRIMITIVE_TYPE : + PrimitiveType primitiveType = (PrimitiveType) type; + return primitiveType.getPrimitiveTypeCode().toString(); + case ASTNode.QUALIFIED_TYPE : + QualifiedType qualifiedType = (QualifiedType) type; + return qualifiedType.getName().getIdentifier(); + case ASTNode.SIMPLE_TYPE : + SimpleType simpleType = (SimpleType) type; + Name name = simpleType.getName(); + if (name.isQualifiedName()) { + QualifiedName qualifiedName = (QualifiedName) name; + return qualifiedName.getName().getIdentifier(); + } + return ((SimpleName) name).getIdentifier(); + } + return Util.EMPTY_STRING; + } + + private Type getType() { + if (this.currentType != null) { + return this.currentType; + } + if (this.variableDeclaration == null) return null; + switch(this.variableDeclaration.getNodeType()) { + case ASTNode.SINGLE_VARIABLE_DECLARATION : + SingleVariableDeclaration singleVariableDeclaration = (SingleVariableDeclaration) this.variableDeclaration; + return singleVariableDeclaration.getType(); + default : + // this is a variable declaration fragment + ASTNode parent = this.variableDeclaration.getParent(); + switch(parent.getNodeType()) { + case ASTNode.VARIABLE_DECLARATION_EXPRESSION : + VariableDeclarationExpression variableDeclarationExpression = (VariableDeclarationExpression) parent; + return variableDeclarationExpression.getType(); + case ASTNode.VARIABLE_DECLARATION_STATEMENT : + VariableDeclarationStatement statement = (VariableDeclarationStatement) parent; + return statement.getType(); + case ASTNode.FIELD_DECLARATION : + FieldDeclaration fieldDeclaration = (FieldDeclaration) parent; + return fieldDeclaration.getType(); + } + } + return null; // should not happen + } +//{ObjectTeams: new lookup-functions + public org.eclipse.jdt.internal.compiler.lookup.TypeBinding getResolvedBinding() { + return this.binding; + } + + /* implement method from ITypeBinding. */ + public boolean isDependentType(boolean onlyRelevant) { + if (this.binding != null) { + if (onlyRelevant) + return RoleTypeBinding.isRoleWithExplicitAnchor(this.binding); + return DependentTypeBinding.isDependentType(this.binding); + } + if ( this.currentType != null + && this.currentType.isParameterizedType()) + return ((ParameterizedType)this.currentType).isDependentType(onlyRelevant); + return false; + } + + /* implement method from ITypeBinding. */ + public String[] getAnchorPath() { + if (this.binding != null) { + if (DependentTypeBinding.isDependentType(this.binding)) + return TypeBinding.getBestNamePath((DependentTypeBinding)this.binding); + } else if ( this.currentType != null + && this.currentType.isParameterizedType() + && ((ParameterizedType)this.currentType).isDependentType(false)) { + return ((ParameterizedType)this.currentType).getAnchorPath(); + } + return new String[0]; + } + + public IMethodMappingBinding[] getResolvedMethodMappings() { + // copy of TypeBinding.getResolvedMethodMappings: + List<IMethodMappingBinding> mappings = new ArrayList<IMethodMappingBinding>(); + if (this.isRole()) { + org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding roleBinding + = (org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding)this.binding; + if (roleBinding.callinCallouts != null) { + for (CallinCalloutBinding mapping : roleBinding.callinCallouts) { + mappings.add(this.resolver.getMethodMappingBinding(mapping)); + } + } + } + IMethodMappingBinding[] result = new IMethodMappingBinding[mappings.size()]; + if (!mappings.isEmpty()) + mappings.toArray(result); + return result; + } +// SH} +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/RecoveredVariableBinding.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/RecoveredVariableBinding.java new file mode 100644 index 000000000..ba512fc63 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/RecoveredVariableBinding.java @@ -0,0 +1,128 @@ +/******************************************************************************* + * Copyright (c) 2007, 2009 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.dom; + +import org.eclipse.jdt.core.IJavaElement; + +/** + * This class represents the recovered binding for a variable + */ +class RecoveredVariableBinding implements IVariableBinding { + + private VariableDeclaration variableDeclaration; + private BindingResolver resolver; + + RecoveredVariableBinding(BindingResolver resolver, VariableDeclaration variableDeclaration) { + this.resolver = resolver; + this.variableDeclaration = variableDeclaration; + } + public Object getConstantValue() { + return null; + } + + public ITypeBinding getDeclaringClass() { + ASTNode parent = this.variableDeclaration.getParent(); + while (parent != null && parent.getNodeType() != ASTNode.TYPE_DECLARATION) { + parent = parent.getParent(); + } + if (parent != null) { + return ((TypeDeclaration) parent).resolveBinding(); + } + return null; + } + + public IMethodBinding getDeclaringMethod() { + ASTNode parent = this.variableDeclaration.getParent(); + while (parent != null && parent.getNodeType() != ASTNode.METHOD_DECLARATION) { + parent = parent.getParent(); + } + if (parent != null) { + return ((MethodDeclaration) parent).resolveBinding(); + } + return null; + } + + public String getName() { + return this.variableDeclaration.getName().getIdentifier(); + } + + public ITypeBinding getType() { + return this.resolver.getTypeBinding(this.variableDeclaration); + } + + public IVariableBinding getVariableDeclaration() { + return this; + } + + public int getVariableId() { + return 0; + } + + public boolean isEnumConstant() { + return false; + } + + public boolean isField() { + return this.variableDeclaration.getParent() instanceof FieldDeclaration; + } + + public boolean isParameter() { + return this.variableDeclaration instanceof SingleVariableDeclaration; + } + + public IAnnotationBinding[] getAnnotations() { + return AnnotationBinding.NoAnnotations; + } + + public IJavaElement getJavaElement() { + return null; + } + + public String getKey() { + StringBuffer buffer = new StringBuffer(); + buffer.append("Recovered#"); //$NON-NLS-1$ + if (this.variableDeclaration != null) { + buffer + .append("variableDeclaration") //$NON-NLS-1$ + .append(this.variableDeclaration.getClass()) + .append(this.variableDeclaration.getName().getIdentifier()) + .append(this.variableDeclaration.getExtraDimensions()); + } + return String.valueOf(buffer); + } + + public int getKind() { + return IBinding.VARIABLE; + } + + public int getModifiers() { + return 0; + } + + public boolean isDeprecated() { + return false; + } + + public boolean isEqualTo(IBinding binding) { + if (binding.isRecovered() && binding.getKind() == IBinding.VARIABLE) { + return getKey().equals(binding.getKey()); + } + return false; + } + + public boolean isRecovered() { + return true; + } + + public boolean isSynthetic() { + return false; + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ReturnStatement.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ReturnStatement.java new file mode 100644 index 000000000..66a01c19a --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ReturnStatement.java @@ -0,0 +1,186 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Return statement AST node type. + * + * <pre> + * ReturnStatement: + * <b>return</b> [ Expression ] <b>;</b> + * </pre> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class ReturnStatement extends Statement { + + /** + * The "expression" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor EXPRESSION_PROPERTY = + new ChildPropertyDescriptor(ReturnStatement.class, "expression", Expression.class, OPTIONAL, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List propertyList = new ArrayList(2); + createPropertyList(ReturnStatement.class, propertyList); + addProperty(EXPRESSION_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The expression; <code>null</code> for none; defaults to none. + */ + private Expression optionalExpression = null; + + /** + * Creates a new AST node for a return statement owned by the + * given AST. By default, the statement has no expression. + * + * @param ast the AST that is to own this node + */ + ReturnStatement(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == EXPRESSION_PROPERTY) { + if (get) { + return getExpression(); + } else { + setExpression((Expression) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return RETURN_STATEMENT; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + ReturnStatement result = new ReturnStatement(target); + result.setSourceRange(getStartPosition(), getLength()); + result.copyLeadingComment(this); + result.setExpression( + (Expression) ASTNode.copySubtree(target, getExpression())); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + acceptChild(visitor, getExpression()); + } + visitor.endVisit(this); + } + + /** + * Returns the expression of this return statement, or + * <code>null</code> if there is none. + * + * @return the expression node, or <code>null</code> if there is none + */ + public Expression getExpression() { + return this.optionalExpression; + } + + /** + * Sets or clears the expression of this return statement. + * + * @param expression the expression node, or <code>null</code> if + * there is none + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setExpression(Expression expression) { + ASTNode oldChild = this.optionalExpression; + preReplaceChild(oldChild, expression, EXPRESSION_PROPERTY); + this.optionalExpression = expression; + postReplaceChild(oldChild, expression, EXPRESSION_PROPERTY); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return super.memSize() + 1 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.optionalExpression == null ? 0 : getExpression().treeSize()); + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/RoleTypeDeclaration.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/RoleTypeDeclaration.java new file mode 100644 index 000000000..7d574b228 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/RoleTypeDeclaration.java @@ -0,0 +1,1029 @@ +/******************************************************************************* + * Copyright (c) 2000, 2010 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 + * $Id$ + * + * Please visit http://www.eclipse.org/objectteams for updates and contact. + * + * Contributors: + * IBM Corporation - initial API and implementation + * Fraunhofer FIRST - extended API and implementation + * Technical University Berlin - extended API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * NEW for OTDT, built in analogy to TypeDeclaration (its superclass) + * + * + * Represents the DOM-ASTNode for a SubType of TypeDeclaration. This node represents a role in a + * compilation unit (a "role file"). + * + * Contained AST elements: + * RoleTypeDeclaration is a Subtyp of TypeDeclaration, so it contains all properties and methods from + * TypeDeclaration, like e.g. TEAM-PROPERTY and getRoles()-Method. This is mandatory, because a role can also + * be a team see <a href="#codeexample1">CodeExample1</a>.<br> + * RoleTypeDeclaration contains also rolespecific properties: + * <dl> + * <dt>1. BaseProperty <dd> adapted baseclass -> TypeDeclaration + * <dt>2. TeamProperty <dd> Team, which includes this Role -> TypeDeclaration + * <dt>3. CallinProperty <dd> a list of all callins which exist inside a role -> List + * <dt>4. CalloutProperty <dd> a list of all callouts which exist inside a role -> List + * </dl> + * + * + * Locations in source code: + * This node is used in BodyDeclaration. + * + * TODO(ike): javadoc is not completed yet... + * + * <a name="codeexample1">CodeExample1</a> + * <pre> + * public team MyTeam1 { + * public team MyRole playedBy MyBaseClass { + * } + * } + * </pre> + * @author ike + */ +public class RoleTypeDeclaration extends TypeDeclaration { + + /** + * The "javadoc" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor JAVADOC_PROPERTY = + internalJavadocPropertyFactory(RoleTypeDeclaration.class); + + /** + * The "modifiers" structural property of this node type (JLS2 API only). + * @since 3.0 + * @deprecated Replaced by {@link #MODIFIERS2_PROPERTY} in the JLS3 API. + */ + public static final SimplePropertyDescriptor MODIFIERS_PROPERTY = + internalModifiersPropertyFactory(RoleTypeDeclaration.class); + + /** + * The "modifiers" structural property of this node type (added in JLS3 API). + * @since 3.0 + */ + public static final ChildListPropertyDescriptor MODIFIERS2_PROPERTY = + internalModifiers2PropertyFactory(RoleTypeDeclaration.class); + + /** + * The "interface" structural property of this node type. + * @since 3.0 + */ + public static final SimplePropertyDescriptor INTERFACE_PROPERTY = + new SimplePropertyDescriptor(RoleTypeDeclaration.class, "interface", boolean.class, MANDATORY); //$NON-NLS-1$ + + /** + * The "team" structural property of this node type. + */ + public static final SimplePropertyDescriptor TEAM_PROPERTY = + new SimplePropertyDescriptor(RoleTypeDeclaration.class, "team", boolean.class, MANDATORY); //$NON-NLS-1$ + + /** + * The "role" structural property of this node type. + */ + public static final SimplePropertyDescriptor ROLE_PROPERTY = + new SimplePropertyDescriptor(RoleTypeDeclaration.class, "role", boolean.class, MANDATORY); //$NON-NLS-1$ + + /** + * The "rolefile" structural property of this node type. + */ + public static final SimplePropertyDescriptor ROLE_FILE_PROPERTY = + new SimplePropertyDescriptor(RoleTypeDeclaration.class, "rolefile", boolean.class, MANDATORY); //$NON-NLS-1$ + + /** + * The "BaseClass" structural property of this node type. + * @since 3.0 + * @deprecated Replaced by {@link #BASECLASS_TYPE_PROPERTY} in the JLS3 API. + */ + public static final ChildPropertyDescriptor BASECLASS_PROPERTY = + new ChildPropertyDescriptor(RoleTypeDeclaration.class, "baseClass", Name.class, OPTIONAL, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "baseClassType" structural property of this node type (added in JLS3 API). + * @since 3.0 + */ + public static final ChildPropertyDescriptor BASECLASS_TYPE_PROPERTY = + new ChildPropertyDescriptor(RoleTypeDeclaration.class, "baseClassType", Type.class, OPTIONAL, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "BaseClass" structural property of this node type. + * @since 3.0 + * @deprecated Replaced by {@link #TEAMCLASS_TYPE_PROPERTY} in the JLS3 API. + */ + public static final ChildPropertyDescriptor TEAMCLASS_PROPERTY = + new ChildPropertyDescriptor(RoleTypeDeclaration.class, "teamClass", Name.class, OPTIONAL, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "baseClassType" structural property of this node type (added in JLS3 API). + * @since 3.0 + */ + public static final ChildPropertyDescriptor TEAMCLASS_TYPE_PROPERTY = + new ChildPropertyDescriptor(RoleTypeDeclaration.class, "teamClassType", Type.class, OPTIONAL, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "name" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor NAME_PROPERTY = + new ChildPropertyDescriptor(RoleTypeDeclaration.class, "name", SimpleName.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "superclass" structural property of this node type (JLS2 API only). + * @since 3.0 + * @deprecated Replaced by {@link #SUPERCLASS_TYPE_PROPERTY} in the JLS3 API. + */ + public static final ChildPropertyDescriptor SUPERCLASS_PROPERTY = + new ChildPropertyDescriptor(RoleTypeDeclaration.class, "superclass", Name.class, OPTIONAL, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "superInterfaces" structural property of this node type (JLS2 API only). + * @since 3.0 + * @deprecated Replaced by {@link #SUPER_INTERFACE_TYPES_PROPERTY} in the JLS3 API. + */ + public static final ChildListPropertyDescriptor SUPER_INTERFACES_PROPERTY = + new ChildListPropertyDescriptor(RoleTypeDeclaration.class, "superInterfaces", Name.class, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "superclassType" structural property of this node type (added in JLS3 API). + * @since 3.0 + */ + public static final ChildPropertyDescriptor SUPERCLASS_TYPE_PROPERTY = + new ChildPropertyDescriptor(RoleTypeDeclaration.class, "superclassType", Type.class, OPTIONAL, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "superInterfaceTypes" structural property of this node type (added in JLS3 API). + * @since 3.0 + */ + public static final ChildListPropertyDescriptor SUPER_INTERFACE_TYPES_PROPERTY = + new ChildListPropertyDescriptor(RoleTypeDeclaration.class, "superInterfaceTypes", Type.class, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "typeParameters" structural property of this node type (added in JLS3 API). + * @since 3.0 + */ + public static final ChildListPropertyDescriptor TYPE_PARAMETERS_PROPERTY = + new ChildListPropertyDescriptor(RoleTypeDeclaration.class, "typeParameters", TypeParameter.class, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "guardPredicate" structural property of this node type (added in JLS3 API). + * @since 0.9.25 + */ + public static final ChildPropertyDescriptor GUARD_PROPERTY = + new ChildPropertyDescriptor(RoleTypeDeclaration.class, "guardPredicate", GuardPredicateDeclaration.class, OPTIONAL, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "bodyDeclarations" structural property of this node type (added in JLS3 API). + * @since 3.0 + */ + public static final ChildListPropertyDescriptor BODY_DECLARATIONS_PROPERTY = + internalBodyDeclarationPropertyFactory(RoleTypeDeclaration.class); + + /** + * The "precedence" structural property. + * @since 0.9.24 + */ + public static final ChildListPropertyDescriptor PRECEDENCE_PROPERTY = + new ChildListPropertyDescriptor(RoleTypeDeclaration.class, "precedence", Name.class, NO_CYCLE_RISK); //$NON-NLS-1$ + + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + * @since 3.0 + */ + @SuppressWarnings("rawtypes") + private static final List PROPERTY_DESCRIPTORS_2_0; + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + * @since 3.0 + */ + @SuppressWarnings("rawtypes") + private static final List PROPERTY_DESCRIPTORS_3_0; + + + + static { + List<StructuralPropertyDescriptor> propertyList = new ArrayList<StructuralPropertyDescriptor>(14); + createPropertyList(RoleTypeDeclaration.class, propertyList); + addProperty(JAVADOC_PROPERTY, propertyList); + addProperty(MODIFIERS_PROPERTY, propertyList); + addProperty(INTERFACE_PROPERTY, propertyList); + addProperty(TEAM_PROPERTY, propertyList); + addProperty(ROLE_PROPERTY, propertyList); + addProperty(BASECLASS_PROPERTY, propertyList); + addProperty(TEAMCLASS_PROPERTY, propertyList); + addProperty(NAME_PROPERTY, propertyList); + addProperty(SUPERCLASS_PROPERTY, propertyList); + addProperty(SUPER_INTERFACES_PROPERTY, propertyList); + addProperty(GUARD_PROPERTY, propertyList); + addProperty(BODY_DECLARATIONS_PROPERTY, propertyList); + addProperty(PRECEDENCE_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS_2_0 = reapPropertyList(propertyList); + + propertyList = new ArrayList<StructuralPropertyDescriptor>(16); + createPropertyList(RoleTypeDeclaration.class, propertyList); + addProperty(JAVADOC_PROPERTY, propertyList); + addProperty(MODIFIERS2_PROPERTY, propertyList); + addProperty(INTERFACE_PROPERTY, propertyList); + addProperty(TEAM_PROPERTY, propertyList); + addProperty(ROLE_PROPERTY, propertyList); + addProperty(ROLE_FILE_PROPERTY, propertyList); + addProperty(BASECLASS_TYPE_PROPERTY, propertyList); + addProperty(TEAMCLASS_TYPE_PROPERTY, propertyList); + addProperty(NAME_PROPERTY, propertyList); + addProperty(TYPE_PARAMETERS_PROPERTY, propertyList); + addProperty(SUPERCLASS_TYPE_PROPERTY, propertyList); + addProperty(SUPER_INTERFACE_TYPES_PROPERTY, propertyList); + addProperty(GUARD_PROPERTY, propertyList); + addProperty(BODY_DECLARATIONS_PROPERTY, propertyList); + addProperty(PRECEDENCE_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS_3_0 = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + @SuppressWarnings("rawtypes") + public static List propertyDescriptors(int apiLevel) + { + if (apiLevel == AST.JLS2) + { + return PROPERTY_DESCRIPTORS_2_0; + } + else + { + return PROPERTY_DESCRIPTORS_3_0; + } + } + + /** + * The optional baseClass name; <code>null</code> if none. + * Defaults to none. Note that this field is not used for + * interface declarations. Not used in 3.0. + */ + private Name optionalBaseClassName = null; + + /** + * The optional baseClass type; <code>null</code> if none. + * Defaults to none. Note that this field is not used for + * interface declarations. Null in JLS2. Added in JLS3. + * @since 3.0 + */ + private Type optionalBaseClassType = null; + + private Name teamClassName = null; + private Type teamClassType = null; + + /** + * @since 1.1.7 + */ + private boolean isRoleFile = false; + + /** + * Creates a new AST node for a type declaration owned by the given + * AST. By default, the type declaration is for a class of an + * unspecified, but legal, name; no modifiers; no javadoc; + * no type parameters; no superclass or superinterfaces; and an empty list + * of body declarations. + * <p> + * N.B. This constructor is package-private; all subclasses must be + * declared in the same package; clients are unable to declare + * additional subclasses. + * </p> + * + * @param ast the AST that is to own this node + */ + RoleTypeDeclaration(AST ast) { + super(ast); + if (ast.apiLevel == AST.JLS2) { + this.superInterfaceNames = new ASTNode.NodeList(SUPER_INTERFACES_PROPERTY); + } + if (ast.apiLevel >= AST.JLS3) { + this.typeParameters = new ASTNode.NodeList(TYPE_PARAMETERS_PROPERTY); + this.superInterfaceTypes = new ASTNode.NodeList(SUPER_INTERFACE_TYPES_PROPERTY); + } + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + * @since 3.0 + */ + @SuppressWarnings("rawtypes") + final List internalStructuralPropertiesForType(int apiLevel) + { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int internalGetSetIntProperty(SimplePropertyDescriptor property, boolean get, int value) + { + if (property == MODIFIERS_PROPERTY) + { + if (get) { + return getModifiers(); + } else { + setModifiers(value); + return 0; + } + } + // allow default implementation to flag the error + return super.internalGetSetIntProperty(property, get, value); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean internalGetSetBooleanProperty(SimplePropertyDescriptor property, boolean get, boolean value) + { + if (property == INTERFACE_PROPERTY) + { + if (get) + { + return isInterface(); + } + else + { + setInterface(value); + return false; + } + } + + if (property == TEAM_PROPERTY) + { + if (get) + { + return isTeam(); + } + else + { + setTeam(value); + return false; + } + } + if (property == ROLE_PROPERTY) + { + if (get) + { + return isRole(); + } + else + { + setRole(value); + return false; + } + } + if (property == ROLE_FILE_PROPERTY) + { + if (get) + { + return isRoleFile(); + } + else + { + setRoleFile(value); + return false; + } + } + // allow default implementation to flag the error + return super.internalGetSetBooleanProperty(property, get, value); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + @Override + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) + { + if (property == JAVADOC_PROPERTY) + { + if (get) { + return getJavadoc(); + } else { + setJavadoc((Javadoc) child); + return null; + } + } + if (property == NAME_PROPERTY) { + if (get) { + return getName(); + } else { + setName((SimpleName) child); + return null; + } + } + if (property == SUPERCLASS_PROPERTY) { + if (get) { + return getSuperclass(); + } else { + setSuperclass((Name) child); + return null; + } + } + if (property == SUPERCLASS_TYPE_PROPERTY) { + if (get) { + return getSuperclassType(); + } else { + setSuperclassType((Type) child); + return null; + } + } + + if (property == BASECLASS_PROPERTY) + { + if (get) + { + return getBaseClass(); + } + else + { + setBaseClass((Name) child); + return null; + } + } + + if (property == BASECLASS_TYPE_PROPERTY) + { + if (get) + { + return getBaseClassType(); + } + else + { + setBaseClassType((Type) child); + return null; + } + } + + if (property == TEAMCLASS_PROPERTY) + { + if (get) + { + return getTeamClass(); + } + else + { + setTeamClass((Name) child); + return null; + } + } + + if (property == TEAMCLASS_TYPE_PROPERTY) + { + if (get) + { + return getTeamClassType(); + } + else + { + setTeamClassType((Type) child); + return null; + } + } + + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + @SuppressWarnings("rawtypes") + final List internalGetChildListProperty(ChildListPropertyDescriptor property) + { + if (property == MODIFIERS2_PROPERTY) + { + return modifiers(); + } + + if (property == TYPE_PARAMETERS_PROPERTY) + { + return typeParameters(); + } + + if (property == SUPER_INTERFACES_PROPERTY) + { + return superInterfaces(); + } + + if (property == SUPER_INTERFACE_TYPES_PROPERTY) + { + return superInterfaceTypes(); + } + + if (property == BODY_DECLARATIONS_PROPERTY) + { + return bodyDeclarations(); + } + + // allow default implementation to flag the error + return super.internalGetChildListProperty(property); + } + + /* (omit javadoc for this method) + * Method declared on BodyDeclaration. + */ + final ChildPropertyDescriptor internalJavadocProperty() + { + return JAVADOC_PROPERTY; + } + + /* (omit javadoc for this method) + * Method declared on BodyDeclaration. + */ + final ChildListPropertyDescriptor internalModifiers2Property() + { + return MODIFIERS2_PROPERTY; + } + + /* (omit javadoc for this method) + * Method declared on BodyDeclaration. + */ + final SimplePropertyDescriptor internalModifiersProperty() + { + return MODIFIERS_PROPERTY; + } + + /* (omit javadoc for this method) + * Method declared on AbstractTypeDeclaration. + */ + final ChildPropertyDescriptor internalNameProperty() + { + return NAME_PROPERTY; + } + + /* (omit javadoc for this method) + * Method declared on AbstractTypeDeclaration. + */ + final ChildListPropertyDescriptor internalBodyDeclarationsProperty() + { + return BODY_DECLARATIONS_PROPERTY; + } + + ChildPropertyDescriptor internalGuardPredicateProperty() { + return GUARD_PROPERTY; + } + + ChildListPropertyDescriptor internalPrecedenceProperty() { + return PRECEDENCE_PROPERTY; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() + { + return ROLE_TYPE_DECLARATION; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + @SuppressWarnings("unchecked") + ASTNode clone0(AST target) + { + RoleTypeDeclaration result = new RoleTypeDeclaration(target); + result.setSourceRange(this.getStartPosition(), this.getLength()); + result.setJavadoc( + (Javadoc) ASTNode.copySubtree(target, getJavadoc())); + if (this.ast.apiLevel == AST.JLS2) + { + result.setModifiers(getModifiers()); + result.setSuperclass( + (Name) ASTNode.copySubtree(target, getSuperclass())); + result.superInterfaces().addAll( + ASTNode.copySubtrees(target, superInterfaces())); + + result.setBaseClass( + (Name) ASTNode.copySubtree(target, getBaseClass())); + + result.setTeamClass( + (Name) ASTNode.copySubtree(target, getTeamClass())); + } + result.setTeam(isTeam()); + result.setRole(isRole()); + result.setRoleFile(isRoleFile()); + result.setName((SimpleName) getName().clone(target)); + if (this.ast.apiLevel >= AST.JLS3) + { + result.modifiers().addAll(ASTNode.copySubtrees(target, modifiers())); + result.typeParameters().addAll( + ASTNode.copySubtrees(target, typeParameters())); + result.setSuperclassType( + (Type) ASTNode.copySubtree(target, getSuperclassType())); + result.superInterfaceTypes().addAll( + ASTNode.copySubtrees(target, superInterfaceTypes())); + + result.setBaseClassType( + (Type) ASTNode.copySubtree(target, getBaseClassType())); + + result.setTeamClassType( + (Type) ASTNode.copySubtree(target, getTeamClassType())); + } + result.setGuardPredicate((GuardPredicateDeclaration)ASTNode.copySubtree(target, getGuardPredicate())); + result.bodyDeclarations().addAll( + ASTNode.copySubtrees(target, bodyDeclarations())); + result.precedences().addAll(ASTNode.copySubtrees(target, precedences())); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) + { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) + { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + if (this.ast.apiLevel == AST.JLS2) { + acceptChild(visitor, getJavadoc()); + acceptChild(visitor, getName()); + acceptChild(visitor, getSuperclass()); + acceptChild(visitor, getBaseClass()); + acceptChildren(visitor, this.superInterfaceNames); + acceptChildren(visitor, this.bodyDeclarations); + } + if (this.ast.apiLevel >= AST.JLS3) { + acceptChild(visitor, getJavadoc()); + acceptChildren(visitor, this.modifiers); + acceptChild(visitor, getName()); + acceptChildren(visitor, this.typeParameters); + acceptChild(visitor, getSuperclassType()); + acceptChild(visitor, getBaseClassType()); + acceptChildren(visitor, this.superInterfaceTypes); + acceptChild(visitor, this.getGuardPredicate()); + acceptChildren(visitor, this.bodyDeclarations); + acceptChildren(visitor, this._precedences); + } + } + visitor.endVisit(this); + } + + /** + * Sets wether this type declaration declares a team class or a class. + * + * @param isTeam <code>true</code> if this is a team class + * declaration, and <code>false</code> if this is a class declaration + */ + public void setTeam(boolean isTeam) + { + preValueChange(TEAM_PROPERTY); + this._isTeam = isTeam; + postValueChange(TEAM_PROPERTY); + } + + /** + * Sets whether this type declaration declares a role class or a class. + * + * @param isRole <code>true</code> if this is a role class + * declaration, and <code>false</code> if this is a class declaration + */ + public void setRole(boolean isRole) + { + preValueChange(ROLE_PROPERTY); + this._isRole = isRole; + postValueChange(ROLE_PROPERTY); + } + + /** + * Sets whether this type declaration resides in a role file. + */ + public void setRoleFile(boolean isRoleFile) + { + preValueChange(ROLE_FILE_PROPERTY); + this.isRoleFile = isRoleFile; + postValueChange(ROLE_FILE_PROPERTY); + } + + /** + * Answer whether this role is a role file. + */ + public boolean isRoleFile() { + return this.isRoleFile; + } + + /** @deprecated replaced by {@link #getBaseClassType()} in JLS3. */ + public Name getBaseClass() + { + supportedOnlyIn2(); + return this.optionalBaseClassName; + } + + public Type getBaseClassType() + { + unsupportedIn2(); + return this.optionalBaseClassType; + } + + /** @deprecated replaced by {@link #getTeamClassType()} in JLS3. */ + public Name getTeamClass() + { + supportedOnlyIn2(); + return this.teamClassName; + } + + public Type getTeamClassType() + { + unsupportedIn2(); + return this.teamClassType; + } + + /** @deprecated use {@link #setBaseClassType(Type)} (JLS3) */ + public void setBaseClass(Name baseClassName) + { + supportedOnlyIn2(); + ASTNode oldChild = this.optionalBaseClassName; + preReplaceChild(oldChild, baseClassName, BASECLASS_PROPERTY); + this.optionalBaseClassName = baseClassName; + postReplaceChild(oldChild, baseClassName, BASECLASS_PROPERTY); + } + + public void setBaseClassType(Type baseClassType) + { + unsupportedIn2(); + ASTNode oldChild = this.optionalBaseClassType; + preReplaceChild(oldChild, baseClassType, BASECLASS_TYPE_PROPERTY); + this.optionalBaseClassType = baseClassType; + postReplaceChild(oldChild, baseClassType, BASECLASS_TYPE_PROPERTY); + } + + /** @deprecated use {@link #setTeamClassType(Type)} (JLS3) */ + public void setTeamClass(Name teamClassName) + { + supportedOnlyIn2(); + ASTNode oldChild = this.teamClassName; + preReplaceChild(oldChild, teamClassName, TEAMCLASS_PROPERTY); + this.teamClassName = teamClassName; + postReplaceChild(oldChild, teamClassName, TEAMCLASS_PROPERTY); + } + + public void setTeamClassType(Type teamClassType) + { + unsupportedIn2(); + ASTNode oldChild = this.teamClassType; + preReplaceChild(oldChild, teamClassType, TEAMCLASS_TYPE_PROPERTY); + this.teamClassType = teamClassType; + postReplaceChild(oldChild, teamClassType, TEAMCLASS_TYPE_PROPERTY); + } + + /** + * Returns the name of the superclass declared in this type + * declaration, or <code>null</code> if there is none (JLS2 API only). + * <p> + * Note that this child is not relevant for interface + * declarations (although it does still figure in subtree + * equality comparisons). + * </p> + * + * @return the superclass name node, or <code>null</code> if + * there is none + * @exception UnsupportedOperationException if this operation is used in + * an AST later than JLS2 + * @deprecated In the JLS3 API, this method is replaced by <code>getSuperclassType</code>, which returns a <code>Type</code> instead of a <code>Name</code>. + */ + public Name getSuperclass() { + supportedOnlyIn2(); + return this.optionalSuperclassName; + } + + /** + * Returns the superclass declared in this type + * declaration, or <code>null</code> if there is none (added in JLS3 API). + * <p> + * Note that this child is not relevant for interface + * declarations (although it does still figure in subtree + * equality comparisons). + * </p> + * + * @return the superclass type node, or <code>null</code> if + * there is none + * @exception UnsupportedOperationException if this operation is used in + * a JLS2 AST + * @since 3.0 + */ + public Type getSuperclassType() { + unsupportedIn2(); + return this.optionalSuperclassType; + } + + /** + * Sets or clears the name of the superclass declared in this type + * declaration (JLS2 API only). + * <p> + * Note that this child is not relevant for interface + * declarations (although it does still figure in subtree + * equality comparisons). + * </p> + * + * @param superclassName the superclass name node, or <code>null</code> if + * there is none + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + * @exception UnsupportedOperationException if this operation is used in + * an AST later than JLS2 + * @deprecated In the JLS3 API, this method is replaced by <code>setType</code>, which expects a <code>Type</code> instead of a <code>Name</code>. + */ + public void setSuperclass(Name superclassName) { + supportedOnlyIn2(); + ASTNode oldChild = this.optionalSuperclassName; + preReplaceChild(oldChild, superclassName, SUPERCLASS_PROPERTY); + this.optionalSuperclassName = superclassName; + postReplaceChild(oldChild, superclassName, SUPERCLASS_PROPERTY); + } + + /** + * Sets or clears the superclass declared in this type + * declaration (added in JLS3 API). + * <p> + * Note that this child is not relevant for interface declarations + * (although it does still figure in subtree equality comparisons). + * </p> + * + * @param superclassType the superclass type node, or <code>null</code> if + * there is none + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + * @exception UnsupportedOperationException if this operation is used in + * a JLS2 AST + * @since 3.0 + */ + public void setSuperclassType(Type superclassType) { + unsupportedIn2(); + ASTNode oldChild = this.optionalSuperclassType; + preReplaceChild(oldChild, superclassType, SUPERCLASS_TYPE_PROPERTY); + this.optionalSuperclassType = superclassType; + postReplaceChild(oldChild, superclassType, SUPERCLASS_TYPE_PROPERTY); + } + + /** + * Returns the ordered list of callout declarations of this type + * declaration. + * <p> + * This convenience method returns this node's body declarations + * with non-methods filtered out. Unlike <code>bodyDeclarations</code>, + * this method does not return a live result. + * </p> + * + * @return the (possibly empty) list of role type declarations + */ + @SuppressWarnings("rawtypes") + public CalloutMappingDeclaration[] getCallOuts() + { + List bd = bodyDeclarations(); + int callOutCount = 0; + for (Iterator it = bd.listIterator(); it.hasNext(); ) + { + if (it.next() instanceof CalloutMappingDeclaration) + { + callOutCount++; + } + } + CalloutMappingDeclaration[] callOuts = new CalloutMappingDeclaration[callOutCount]; + int next = 0; + for (Iterator it = bd.listIterator(); it.hasNext(); ) + { + Object decl = it.next(); + if (decl instanceof CalloutMappingDeclaration) + { + callOuts[next++] = (CalloutMappingDeclaration) decl; + } + } + return callOuts; + } + + /** + * Returns the ordered list of CallIn declarations of this type + * declaration. + * <p> + * This convenience method returns this node's body declarations + * with non-methods filtered out. Unlike <code>bodyDeclarations</code>, + * this method does not return a live result. + * </p> + * + * @return the (possibly empty) list of role type declarations + */ + @SuppressWarnings("rawtypes") + public CallinMappingDeclaration[] getCallIns() + { + List bd = bodyDeclarations(); + int callInCount = 0; + for (Iterator it = bd.listIterator(); it.hasNext(); ) + { + if (it.next() instanceof CallinMappingDeclaration) + { + callInCount++; + } + } + CallinMappingDeclaration[] callIns = new CallinMappingDeclaration[callInCount]; + int next = 0; + for (Iterator it = bd.listIterator(); it.hasNext(); ) + { + Object decl = it.next(); + if (decl instanceof CallinMappingDeclaration) + { + callIns[next++] = (CallinMappingDeclaration) decl; + } + } + return callIns; + } + + + + + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + @SuppressWarnings({ "nls", "rawtypes" }) + void appendDebugString(StringBuffer buffer) + { + buffer.append("RoleTypeDeclaration[\n"); + buffer.append("class "); + buffer.append(getName().getIdentifier()); + buffer.append("\n"); + if (this.optionalGuardPredicate != null) { + getGuardPredicate().appendDebugString(buffer); + buffer.append("\n"); + } + for (Iterator it = bodyDeclarations().iterator(); it.hasNext();) { + BodyDeclaration d = (BodyDeclaration) it.next(); + d.appendDebugString(buffer); + if (it.hasNext()) { + buffer.append(";\n"); + } + } + buffer.append("]"); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() + { + return super.memSize() + 12 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() + { + return memSize() + + (this.optionalDocComment == null ? 0 : getJavadoc().treeSize()) + + (this.modifiers == null ? 0 : this.modifiers.listSize()) + + (this.typeName == null ? 0 : getName().treeSize()) + + (this.typeParameters == null ? 0 : this.typeParameters.listSize()) + + (this.optionalSuperclassName == null ? 0 : getSuperclass().treeSize()) + + (this.optionalSuperclassType == null ? 0 : getSuperclassType().treeSize()) + + (this.superInterfaceNames == null ? 0 : this.superInterfaceNames.listSize()) + + (this.superInterfaceTypes == null ? 0 : this.superInterfaceTypes.listSize()) + + this.bodyDeclarations.listSize() + + this._precedences.listSize() + + (this.optionalBaseClassName == null ? 0 : this.optionalBaseClassName.treeSize()) + + (this.optionalBaseClassType == null ? 0 : this.optionalBaseClassType.treeSize()) + + (this.teamClassName== null ? 0 : this.teamClassName.treeSize()) + + (this.teamClassType == null ? 0 : this.teamClassType.treeSize()) + + (this.optionalGuardPredicate == null ? 0 : this.optionalGuardPredicate.treeSize()); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SimpleName.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SimpleName.java new file mode 100644 index 000000000..42cd9a155 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SimpleName.java @@ -0,0 +1,315 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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 + * $Id: SimpleName.java 19895 2009-04-15 13:52:23Z stephan $ + * + * Contributors: + * IBM Corporation - initial API and implementation + * Fraunhofer FIRST - extended API and implementation + * Technical University Berlin - extended API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jdt.core.compiler.InvalidInputException; +import org.eclipse.jdt.internal.compiler.parser.Scanner; +import org.eclipse.jdt.internal.compiler.parser.TerminalTokens; + +/** + * AST node for a simple name. A simple name is an identifier other than + * a keyword, boolean literal ("true", "false") or null literal ("null"). + * <pre> + * SimpleName: + * Identifier + * </pre> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class SimpleName extends Name { + + /** + * The "identifier" structural property of this node type. + * + * @since 3.0 + */ + public static final SimplePropertyDescriptor IDENTIFIER_PROPERTY = + new SimplePropertyDescriptor(SimpleName.class, "identifier", String.class, MANDATORY); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + * @since 3.0 + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List propertyList = new ArrayList(2); + createPropertyList(SimpleName.class, propertyList); + addProperty(IDENTIFIER_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the AST.JLS* constants + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * An unspecified (but externally observable) legal Java identifier. + */ + private static final String MISSING_IDENTIFIER = "MISSING";//$NON-NLS-1$ + + /** + * The identifier; defaults to a unspecified, legal Java identifier. + */ + private String identifier = MISSING_IDENTIFIER; + + /** + * Creates a new AST node for a simple name owned by the given AST. + * The new node has an unspecified, legal Java identifier. + * <p> + * N.B. This constructor is package-private; all subclasses must be + * declared in the same package; clients are unable to declare + * additional subclasses. + * </p> + * + * @param ast the AST that is to own this node + */ + SimpleName(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + * @since 3.0 + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final Object internalGetSetObjectProperty(SimplePropertyDescriptor property, boolean get, Object value) { + if (property == IDENTIFIER_PROPERTY) { + if (get) { + return getIdentifier(); + } else { + setIdentifier((String) value); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetObjectProperty(property, get, value); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return SIMPLE_NAME; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + SimpleName result = new SimpleName(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setIdentifier(getIdentifier()); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + visitor.visit(this); + visitor.endVisit(this); + } + + /** + * Returns this node's identifier. + * + * @return the identifier of this node + */ + public String getIdentifier() { + return this.identifier; + } + + /** + * Sets the identifier of this node to the given value. + * The identifier should be legal according to the rules + * of the Java language. Note that keywords are not legal + * identifiers. + * <p> + * Note that the list of keywords may depend on the version of the + * language (determined when the AST object was created). + * </p> + * + * @param identifier the identifier of this node + * @exception IllegalArgumentException if the identifier is invalid + */ + public void setIdentifier(String identifier) { + // update internalSetIdentifier if this is changed + if (identifier == null) { + throw new IllegalArgumentException(); + } + Scanner scanner = this.ast.scanner; + char[] source = identifier.toCharArray(); + scanner.setSource(source); + final int length = source.length; + scanner.resetTo(0, length - 1); + try { + int tokenType = scanner.scanIdentifier(); +//{ObjectTeams: treat like an Identifier: + switch (tokenType) { + case TerminalTokens.TokenNamebase: + case TerminalTokens.TokenNamewhen: + case TerminalTokens.TokenNamethis: // like in: T.this.anchor.Type + tokenType = TerminalTokens.TokenNameIdentifier; + } +//SH} + if (tokenType != TerminalTokens.TokenNameIdentifier) { + throw new IllegalArgumentException(); + } + if (scanner.currentPosition != length) { + // this is the case when there is only one identifier see 87849 + throw new IllegalArgumentException(); + } + } catch(InvalidInputException e) { + throw new IllegalArgumentException(); + } + preValueChange(IDENTIFIER_PROPERTY); + this.identifier = identifier; + postValueChange(IDENTIFIER_PROPERTY); + } + + /* (omit javadoc for this method) + * This method is a copy of setIdentifier(String) that doesn't do any validation. + */ + void internalSetIdentifier(String ident) { + preValueChange(IDENTIFIER_PROPERTY); + this.identifier = ident; + postValueChange(IDENTIFIER_PROPERTY); + } + + /** + * Returns whether this simple name represents a name that is being defined, + * as opposed to one being referenced. The following positions are considered + * ones where a name is defined: + * <ul> + * <li>The type name in a <code>TypeDeclaration</code> node.</li> + * <li>The method name in a <code>MethodDeclaration</code> node + * providing <code>isConstructor</code> is <code>false</code>.</li> + * <li>The variable name in any type of <code>VariableDeclaration</code> + * node.</li> + * <li>The enum type name in a <code>EnumDeclaration</code> node.</li> + * <li>The enum constant name in an <code>EnumConstantDeclaration</code> + * node.</li> + * <li>The variable name in an <code>EnhancedForStatement</code> + * node.</li> + * <li>The type variable name in a <code>TypeParameter</code> + * node.</li> + * <li>The type name in an <code>AnnotationTypeDeclaration</code> node.</li> + * <li>The member name in an <code>AnnotationTypeMemberDeclaration</code> node.</li> + * </ul> + * <p> + * Note that this is a convenience method that simply checks whether + * this node appears in the declaration position relative to its parent. + * It always returns <code>false</code> if this node is unparented. + * </p> + * + * @return <code>true</code> if this node declares a name, and + * <code>false</code> otherwise + */ + public boolean isDeclaration() { + StructuralPropertyDescriptor d = getLocationInParent(); + if (d == null) { + // unparented node + return false; + } + ASTNode parent = getParent(); + if (parent instanceof TypeDeclaration) { + return (d == TypeDeclaration.NAME_PROPERTY); + } + if (parent instanceof MethodDeclaration) { + MethodDeclaration p = (MethodDeclaration) parent; + // could be the name of the method or constructor + return !p.isConstructor() && (d == MethodDeclaration.NAME_PROPERTY); + } + if (parent instanceof SingleVariableDeclaration) { + return (d == SingleVariableDeclaration.NAME_PROPERTY); + } + if (parent instanceof VariableDeclarationFragment) { + return (d == VariableDeclarationFragment.NAME_PROPERTY); + } + if (parent instanceof EnumDeclaration) { + return (d == EnumDeclaration.NAME_PROPERTY); + } + if (parent instanceof EnumConstantDeclaration) { + return (d == EnumConstantDeclaration.NAME_PROPERTY); + } + if (parent instanceof TypeParameter) { + return (d == TypeParameter.NAME_PROPERTY); + } + if (parent instanceof AnnotationTypeDeclaration) { + return (d == AnnotationTypeDeclaration.NAME_PROPERTY); + } + if (parent instanceof AnnotationTypeMemberDeclaration) { + return (d == AnnotationTypeMemberDeclaration.NAME_PROPERTY); + } + return false; + } + + /* (omit javadoc for this method) + * Method declared on Name. + */ + void appendName(StringBuffer buffer) { + buffer.append(getIdentifier()); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + int size = BASE_NAME_NODE_SIZE + 2 * 4; + if (this.identifier != MISSING_IDENTIFIER) { + // everything but our missing id costs + size += stringSize(this.identifier); + } + return size; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return memSize(); + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SimplePropertyDescriptor.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SimplePropertyDescriptor.java new file mode 100644 index 000000000..e30c3019e --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SimplePropertyDescriptor.java @@ -0,0 +1,83 @@ +/******************************************************************************* + * Copyright (c) 2004, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.dom; + +/** + * Descriptor for a simple property of an AST node. + * A simple property is one whose value is a + * primitive type (such as <code>int</code> or <code>boolean</code>) + * or some simple value type (such as <code>String</code> or + * <code>InfixExpression.Operator</code>). + * + * @see org.eclipse.jdt.core.dom.ASTNode#getStructuralProperty(StructuralPropertyDescriptor) + * @see org.eclipse.jdt.core.dom.ASTNode#setStructuralProperty(StructuralPropertyDescriptor, Object) + * @since 3.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public final class SimplePropertyDescriptor extends StructuralPropertyDescriptor { + + /** + * Value type. For example, for a node type like + * SingleVariableDeclaration, the modifiers property is int.class + */ + private final Class valueType; + + /** + * Indicates whether a value is mandatory. A property value is allowed + * to be <code>null</code> only if it is not mandatory. + */ + private final boolean mandatory; + + /** + * Creates a new simple property descriptor with the given property id. + * Note that this constructor is declared package-private so that + * property descriptors can only be created by the AST + * implementation. + * + * @param nodeClass concrete AST node type that owns this property + * @param propertyId the property id + * @param valueType the value type of this property + * @param mandatory <code>true</code> if the property is mandatory, + * and <code>false</code> if it is may be <code>null</code> + */ + SimplePropertyDescriptor(Class nodeClass, String propertyId, Class valueType, boolean mandatory) { + super(nodeClass, propertyId); + if (valueType == null || ASTNode.class.isAssignableFrom(valueType)) { + throw new IllegalArgumentException(); + } + this.valueType = valueType; + this.mandatory = mandatory; + } + + /** + * Returns the value type of this property. + * <p> + * For example, for a node type like SingleVariableDeclaration, + * the "modifiers" property returns <code>int.class</code>. + * </p> + * + * @return the value type of the property + */ + public Class getValueType() { + return this.valueType; + } + + /** + * Returns whether this property is mandatory. A property value + * is not allowed to be <code>null</code> if it is mandatory. + * + * @return <code>true</code> if the property is mandatory, + * and <code>false</code> if it is may be <code>null</code> + */ + public boolean isMandatory() { + return this.mandatory; + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SimpleType.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SimpleType.java new file mode 100644 index 000000000..2050281bc --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SimpleType.java @@ -0,0 +1,198 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Type node for a named class type, a named interface type, or a type variable. + * <p> + * This kind of node is used to convert a name (<code>Name</code>) into a type + * (<code>Type</code>) by wrapping it. + * </p> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class SimpleType extends Type { + + /** + * The "name" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor NAME_PROPERTY = + new ChildPropertyDescriptor(SimpleType.class, "name", Name.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List propertyList = new ArrayList(2); + createPropertyList(SimpleType.class, propertyList); + addProperty(NAME_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The type name node; lazily initialized; defaults to a type with + * an unspecfied, but legal, name. + */ + private Name typeName = null; + + /** + * Creates a new unparented node for a simple type owned by the given AST. + * By default, an unspecified, but legal, name. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + SimpleType(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == NAME_PROPERTY) { + if (get) { + return getName(); + } else { + setName((Name) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return SIMPLE_TYPE; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + SimpleType result = new SimpleType(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setName((Name) (getName()).clone(target)); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + acceptChild(visitor, getName()); + } + visitor.endVisit(this); + } + + /** + * Returns the name of this simple type. + * + * @return the name of this simple type + */ + public Name getName() { + if (this.typeName == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.typeName == null) { + preLazyInit(); + this.typeName = new SimpleName(this.ast); + postLazyInit(this.typeName, NAME_PROPERTY); + } + } + } + return this.typeName; + } + + /** + * Sets the name of this simple type to the given name. + * + * @param typeName the new name of this simple type + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public void setName(Name typeName) { + if (typeName == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.typeName; + preReplaceChild(oldChild, typeName, NAME_PROPERTY); + this.typeName = typeName; + postReplaceChild(oldChild, typeName, NAME_PROPERTY); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + // treat Code as free + return BASE_NODE_SIZE + 1 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.typeName == null ? 0 : getName().treeSize()); + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SingleMemberAnnotation.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SingleMemberAnnotation.java new file mode 100644 index 000000000..a6ed58525 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SingleMemberAnnotation.java @@ -0,0 +1,226 @@ +/******************************************************************************* + * Copyright (c) 2004, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Single member annotation node (added in JLS3 API). The single member annotation + * "@foo(bar)" is equivalent to the normal annotation "@foo(value=bar)". + * <p> + * <pre> + * SingleMemberAnnotation: + * <b>@</b> TypeName <b>(</b> Expression <b>)</b> + * </pre> + * Within annotations, only certain kinds of expressions are meaningful, + * including other annotations. + * </p> + * + * @since 3.1 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public final class SingleMemberAnnotation extends Annotation { + + /** + * The "typeName" structural property of this node type. + */ + public static final ChildPropertyDescriptor TYPE_NAME_PROPERTY = + internalTypeNamePropertyFactory(SingleMemberAnnotation.class); + + /** + * The "value" structural property of this node type. + */ + public static final ChildPropertyDescriptor VALUE_PROPERTY = + new ChildPropertyDescriptor(SingleMemberAnnotation.class, "value", Expression.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List propertyList = new ArrayList(3); + createPropertyList(SingleMemberAnnotation.class, propertyList); + addProperty(TYPE_NAME_PROPERTY, propertyList); + addProperty(VALUE_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the AST.JLS* constants + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The value; lazily initialized; defaults to a unspecified, but legal, + * expression. + */ + private Expression value = null; + + /** + * Creates a new unparented normal annotation node owned + * by the given AST. By default, the annotation has an + * unspecified type name and an unspecified value. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + SingleMemberAnnotation(AST ast) { + super(ast); + unsupportedIn2(); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == TYPE_NAME_PROPERTY) { + if (get) { + return getTypeName(); + } else { + setTypeName((Name) child); + return null; + } + } + if (property == VALUE_PROPERTY) { + if (get) { + return getValue(); + } else { + setValue((Expression) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on BodyDeclaration. + */ + final ChildPropertyDescriptor internalTypeNameProperty() { + return TYPE_NAME_PROPERTY; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return SINGLE_MEMBER_ANNOTATION; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + SingleMemberAnnotation result = new SingleMemberAnnotation(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setTypeName((Name) ASTNode.copySubtree(target, getTypeName())); + result.setValue((Expression) ASTNode.copySubtree(target, getValue())); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + acceptChild(visitor, getTypeName()); + acceptChild(visitor, getValue()); + } + visitor.endVisit(this); + } + + /** + * Returns the value of this annotation. + * + * @return the value node + */ + public Expression getValue() { + if (this.value == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.value == null) { + preLazyInit(); + this.value = new SimpleName(this.ast); + postLazyInit(this.value, VALUE_PROPERTY); + } + } + } + return this.value; + } + + /** + * Sets the value of this annotation. + * + * @param value the new value + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setValue(Expression value) { + if (value == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.value; + preReplaceChild(oldChild, value, VALUE_PROPERTY); + this.value = value; + postReplaceChild(oldChild, value, VALUE_PROPERTY); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return super.memSize() + 1 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.typeName == null ? 0 : getTypeName().treeSize()) + + (this.value == null ? 0 : getValue().treeSize()); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SingleVariableDeclaration.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SingleVariableDeclaration.java new file mode 100644 index 000000000..3cf671763 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SingleVariableDeclaration.java @@ -0,0 +1,636 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * Single variable declaration AST node type. Single variable + * declaration nodes are used in a limited number of places, including formal + * parameter lists and catch clauses. They are not used for field declarations + * and regular variable declaration statements. + * For JLS2: + * <pre> + * SingleVariableDeclaration: + * { Modifier } Type Identifier { <b>[</b><b>]</b> } [ <b>=</b> Expression ] + * </pre> + * For JLS3, the modifier flags were replaced by + * a list of modifier nodes (intermixed with annotations), and the variable arity + * indicator was added: + * <pre> + * SingleVariableDeclaration: + * { ExtendedModifier } Type [ <b>...</b> ] Identifier { <b>[</b><b>]</b> } [ <b>=</b> Expression ] + * </pre> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class SingleVariableDeclaration extends VariableDeclaration { + + /** + * The "modifiers" structural property of this node type (JLS2 API only). + * @since 3.0 + */ + public static final SimplePropertyDescriptor MODIFIERS_PROPERTY = + new SimplePropertyDescriptor(SingleVariableDeclaration.class, "modifiers", int.class, MANDATORY); //$NON-NLS-1$ + + /** + * The "modifiers" structural property of this node type (added in JLS3 API). + * @since 3.1 + */ + public static final ChildListPropertyDescriptor MODIFIERS2_PROPERTY = + new ChildListPropertyDescriptor(SingleVariableDeclaration.class, "modifiers", IExtendedModifier.class, CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "name" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor NAME_PROPERTY = + new ChildPropertyDescriptor(SingleVariableDeclaration.class, "name", SimpleName.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "type" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor TYPE_PROPERTY = + new ChildPropertyDescriptor(SingleVariableDeclaration.class, "type", Type.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "varargs" structural property of this node type (added in JLS3 API). + * @since 3.1 + */ + public static final SimplePropertyDescriptor VARARGS_PROPERTY = + new SimplePropertyDescriptor(SingleVariableDeclaration.class, "varargs", boolean.class, MANDATORY); //$NON-NLS-1$ + + /** + * The "extraDimensions" structural property of this node type. + * @since 3.0 + */ + public static final SimplePropertyDescriptor EXTRA_DIMENSIONS_PROPERTY = + new SimplePropertyDescriptor(SingleVariableDeclaration.class, "extraDimensions", int.class, MANDATORY); //$NON-NLS-1$ + + /** + * The "initializer" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor INITIALIZER_PROPERTY = + new ChildPropertyDescriptor(SingleVariableDeclaration.class, "initializer", Expression.class, OPTIONAL, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + * @since 3.0 + */ + private static final List PROPERTY_DESCRIPTORS_2_0; + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + * @since 3.1 + */ + private static final List PROPERTY_DESCRIPTORS_3_0; + + static { + List propertyList = new ArrayList(6); + createPropertyList(SingleVariableDeclaration.class, propertyList); + addProperty(MODIFIERS_PROPERTY, propertyList); + addProperty(TYPE_PROPERTY, propertyList); + addProperty(NAME_PROPERTY, propertyList); + addProperty(EXTRA_DIMENSIONS_PROPERTY, propertyList); + addProperty(INITIALIZER_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS_2_0 = reapPropertyList(propertyList); + + propertyList = new ArrayList(7); + createPropertyList(SingleVariableDeclaration.class, propertyList); + addProperty(MODIFIERS2_PROPERTY, propertyList); + addProperty(TYPE_PROPERTY, propertyList); + addProperty(VARARGS_PROPERTY, propertyList); + addProperty(NAME_PROPERTY, propertyList); + addProperty(EXTRA_DIMENSIONS_PROPERTY, propertyList); + addProperty(INITIALIZER_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS_3_0 = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + if (apiLevel == AST.JLS2_INTERNAL) { + return PROPERTY_DESCRIPTORS_2_0; + } else { + return PROPERTY_DESCRIPTORS_3_0; + } + } + + /** + * The extended modifiers (element type: <code>IExtendedModifier</code>). + * Null in JLS2. Added in JLS3; defaults to an empty list + * (see constructor). + * + * @since 3.1 + */ + private ASTNode.NodeList modifiers = null; + + /** + * The modifiers; bit-wise or of Modifier flags. + * Defaults to none. Not used in 3.0. + */ + private int modifierFlags = Modifier.NONE; + + /** + * The variable name; lazily initialized; defaults to a unspecified, + * legal Java identifier. + */ + private SimpleName variableName = null; + + /** + * The type; lazily initialized; defaults to a unspecified, + * legal type. + */ + private Type type = null; + + /** + * Indicates the last parameter of a variable arity method; + * defaults to false. + * + * @since 3.1 + */ + private boolean variableArity = false; + + /** + * The number of extra array dimensions that appear after the variable; + * defaults to 0. + * + * @since 2.1 + */ + private int extraArrayDimensions = 0; + + /** + * The initializer expression, or <code>null</code> if none; + * defaults to none. + */ + private Expression optionalInitializer = null; + + /** + * Creates a new AST node for a variable declaration owned by the given + * AST. By default, the variable declaration has: no modifiers, an + * unspecified (but legal) type, an unspecified (but legal) variable name, + * 0 dimensions after the variable; no initializer; not variable arity. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + SingleVariableDeclaration(AST ast) { + super(ast); + if (ast.apiLevel >= AST.JLS3) { + this.modifiers = new ASTNode.NodeList(MODIFIERS2_PROPERTY); + } + } + + /* (omit javadoc for this method) + * Method declared on VariableDeclaration. + * @since 3.1 + */ + final SimplePropertyDescriptor internalExtraDimensionsProperty() { + return EXTRA_DIMENSIONS_PROPERTY; + } + + /* (omit javadoc for this method) + * Method declared on VariableDeclaration. + * @since 3.1 + */ + final ChildPropertyDescriptor internalInitializerProperty() { + return INITIALIZER_PROPERTY; + } + + /* (omit javadoc for this method) + * Method declared on VariableDeclaration. + * @since 3.1 + */ + final ChildPropertyDescriptor internalNameProperty() { + return NAME_PROPERTY; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int internalGetSetIntProperty(SimplePropertyDescriptor property, boolean get, int value) { + if (property == MODIFIERS_PROPERTY) { + if (get) { + return getModifiers(); + } else { + setModifiers(value); + return 0; + } + } + if (property == EXTRA_DIMENSIONS_PROPERTY) { + if (get) { + return getExtraDimensions(); + } else { + setExtraDimensions(value); + return 0; + } + } + // allow default implementation to flag the error + return super.internalGetSetIntProperty(property, get, value); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean internalGetSetBooleanProperty(SimplePropertyDescriptor property, boolean get, boolean value) { + if (property == VARARGS_PROPERTY) { + if (get) { + return isVarargs(); + } else { + setVarargs(value); + return false; + } + } + // allow default implementation to flag the error + return super.internalGetSetBooleanProperty(property, get, value); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == NAME_PROPERTY) { + if (get) { + return getName(); + } else { + setName((SimpleName) child); + return null; + } + } + if (property == TYPE_PROPERTY) { + if (get) { + return getType(); + } else { + setType((Type) child); + return null; + } + } + if (property == INITIALIZER_PROPERTY) { + if (get) { + return getInitializer(); + } else { + setInitializer((Expression) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalGetChildListProperty(ChildListPropertyDescriptor property) { + if (property == MODIFIERS2_PROPERTY) { + return modifiers(); + } + // allow default implementation to flag the error + return super.internalGetChildListProperty(property); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return SINGLE_VARIABLE_DECLARATION; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + SingleVariableDeclaration result = new SingleVariableDeclaration(target); + result.setSourceRange(getStartPosition(), getLength()); + if (this.ast.apiLevel == AST.JLS2_INTERNAL) { + result.setModifiers(getModifiers()); + } else { + result.modifiers().addAll(ASTNode.copySubtrees(target, modifiers())); + result.setVarargs(isVarargs()); + } + result.setType((Type) getType().clone(target)); + result.setExtraDimensions(getExtraDimensions()); + result.setName((SimpleName) getName().clone(target)); + result.setInitializer( + (Expression) ASTNode.copySubtree(target, getInitializer())); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + if (this.ast.apiLevel >= AST.JLS3) { + acceptChildren(visitor, this.modifiers); + } + acceptChild(visitor, getType()); + acceptChild(visitor, getName()); + acceptChild(visitor, getInitializer()); + } + visitor.endVisit(this); + } + + /** + * Returns the live ordered list of modifiers and annotations + * of this declaration (added in JLS3 API). + * <p> + * Note that the final modifier is the only meaningful modifier for local + * variable and formal parameter declarations. + * </p> + * + * @return the live list of modifiers and annotations + * (element type: <code>IExtendedModifier</code>) + * @exception UnsupportedOperationException if this operation is used in + * a JLS2 AST + * @since 3.1 + */ + public List modifiers() { + // more efficient than just calling unsupportedIn2() to check + if (this.modifiers == null) { + unsupportedIn2(); + } + return this.modifiers; + } + + /** + * Returns the modifiers explicitly specified on this declaration. + * <p> + * In the JLS3 API, this method is a convenience method that + * computes these flags from <code>modifiers()</code>. + * </p> + * + * @return the bit-wise or of <code>Modifier</code> constants + * @see Modifier + */ + public int getModifiers() { + // more efficient than checking getAST().API_LEVEL + if (this.modifiers == null) { + // JLS2 behavior - bona fide property + return this.modifierFlags; + } else { + // JLS3 behavior - convenient method + // performance could be improved by caching computed flags + // but this would require tracking changes to this.modifiers + int computedModifierFlags = Modifier.NONE; + for (Iterator it = modifiers().iterator(); it.hasNext(); ) { + Object x = it.next(); + if (x instanceof Modifier) { + computedModifierFlags |= ((Modifier) x).getKeyword().toFlagValue(); + } + } + return computedModifierFlags; + } + } + + /** + * Sets the modifiers explicitly specified on this declaration (JLS2 API only). + * <p> + * The following modifiers are meaningful for fields: public, private, protected, + * static, final, volatile, and transient. For local variable and formal + * parameter declarations, the only meaningful modifier is final. + * </p> + * + * @param modifiers the given modifiers (bit-wise or of <code>Modifier</code> constants) + * @exception UnsupportedOperationException if this operation is used in + * an AST later than JLS2 + * @see Modifier + * @deprecated In the JLS3 API, this method is replaced by + * {@link #modifiers()} which contains a list of a <code>Modifier</code> nodes. + */ + public void setModifiers(int modifiers) { + internalSetModifiers(modifiers); + } + + /** + * Internal synonym for deprecated method. Used to avoid + * deprecation warnings. + * @since 3.1 + */ + /*package*/ final void internalSetModifiers(int pmodifiers) { + supportedOnlyIn2(); + preValueChange(MODIFIERS_PROPERTY); + this.modifierFlags = pmodifiers; + postValueChange(MODIFIERS_PROPERTY); + } + + /* (omit javadoc for this method) + * Method declared on VariableDeclaration. + */ + public SimpleName getName() { + if (this.variableName == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.variableName == null) { + preLazyInit(); + this.variableName = new SimpleName(this.ast); + postLazyInit(this.variableName, NAME_PROPERTY); + } + } + } + return this.variableName; + } + + /* (omit javadoc for this method) + * Method declared on VariableDeclaration. + */ + public void setName(SimpleName variableName) { + if (variableName == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.variableName; + preReplaceChild(oldChild, variableName, NAME_PROPERTY); + this.variableName = variableName; + postReplaceChild(oldChild, variableName, NAME_PROPERTY); + } + + /** + * Returns the type of the variable declared in this variable declaration, + * exclusive of any extra array dimensions. + * + * @return the type + */ + public Type getType() { + if (this.type == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.type == null) { + preLazyInit(); + this.type = this.ast.newPrimitiveType(PrimitiveType.INT); + postLazyInit(this.type, TYPE_PROPERTY); + } + } + } + return this.type; + } + + /** + * Sets the type of the variable declared in this variable declaration to + * the given type, exclusive of any extra array dimensions. + * + * @param type the new type + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public void setType(Type type) { + if (type == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.type; + preReplaceChild(oldChild, type, TYPE_PROPERTY); + this.type = type; + postReplaceChild(oldChild, type, TYPE_PROPERTY); + } + + /** + * Returns whether this declaration declares the last parameter of + * a variable arity method (added in JLS3 API). + * <p> + * Note that the binding for the type <code>Foo</code>in the vararg method + * declaration <code>void fun(Foo... args)</code> is always for the type as + * written; i.e., the type binding for <code>Foo</code>. However, if you + * navigate from the method declaration to its method binding to the + * type binding for its last parameter, the type binding for the vararg + * parameter is always an array type (i.e., <code>Foo[]</code>) reflecting + * the way vararg methods get compiled. + * </p> + * + * @return <code>true</code> if this is a variable arity parameter declaration, + * and <code>false</code> otherwise + * @exception UnsupportedOperationException if this operation is used in + * a JLS2 AST + * @since 3.1 + */ + public boolean isVarargs() { + // more efficient than just calling unsupportedIn2() to check + if (this.modifiers == null) { + unsupportedIn2(); + } + return this.variableArity; + } + + /** + * Sets whether this declaration declares the last parameter of + * a variable arity method (added in JLS3 API). + * + * @param variableArity <code>true</code> if this is a variable arity + * parameter declaration, and <code>false</code> otherwise + * @since 3.1 + */ + public void setVarargs(boolean variableArity) { + // more efficient than just calling unsupportedIn2() to check + if (this.modifiers == null) { + unsupportedIn2(); + } + preValueChange(VARARGS_PROPERTY); + this.variableArity = variableArity; + postValueChange(VARARGS_PROPERTY); + } + + /* (omit javadoc for this method) + * Method declared on VariableDeclaration. + * @since 2.1 + */ + public int getExtraDimensions() { + return this.extraArrayDimensions; + } + + /* (omit javadoc for this method) + * Method declared on VariableDeclaration. + * @since 2.1 + */ + public void setExtraDimensions(int dimensions) { + if (dimensions < 0) { + throw new IllegalArgumentException(); + } + preValueChange(EXTRA_DIMENSIONS_PROPERTY); + this.extraArrayDimensions = dimensions; + postValueChange(EXTRA_DIMENSIONS_PROPERTY); + } + + /* (omit javadoc for this method) + * Method declared on VariableDeclaration. + */ + public Expression getInitializer() { + return this.optionalInitializer; + } + + /* (omit javadoc for this method) + * Method declared on VariableDeclaration. + */ + public void setInitializer(Expression initializer) { + // a SingleVariableDeclaration may occur inside an Expression + // must check cycles + ASTNode oldChild = this.optionalInitializer; + preReplaceChild(oldChild, initializer,INITIALIZER_PROPERTY); + this.optionalInitializer = initializer; + postReplaceChild(oldChild, initializer,INITIALIZER_PROPERTY); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + // treat Operator as free + return BASE_NODE_SIZE + 7 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.modifiers == null ? 0 : this.modifiers.listSize()) + + (this.type == null ? 0 : getType().treeSize()) + + (this.variableName == null ? 0 : getName().treeSize()) + + (this.optionalInitializer == null ? 0 : getInitializer().treeSize()); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Statement.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Statement.java new file mode 100644 index 000000000..31fff4779 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Statement.java @@ -0,0 +1,210 @@ +/******************************************************************************* + * Copyright (c) 2000, 2009 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import org.eclipse.jdt.core.compiler.InvalidInputException; +import org.eclipse.jdt.internal.compiler.parser.Scanner; +import org.eclipse.jdt.internal.compiler.parser.TerminalTokens; + +/** + * Abstract base class of AST nodes that represent statements. + * There are many kinds of statements. + * <p> + * The grammar combines both Statement and BlockStatement. + * For JLS2: + * <pre> + * Statement: + * Block + * IfStatement + * ForStatement + * WhileStatement + * DoStatement + * TryStatement + * SwitchStatement + * SynchronizedStatement + * ReturnStatement + * ThrowStatement + * BreakStatement + * ContinueStatement + * EmptyStatement + * ExpressionStatement + * LabeledStatement + * AssertStatement + * VariableDeclarationStatement + * TypeDeclarationStatement + * ConstructorInvocation + * SuperConstructorInvocation + * </pre> + * For JLS3, an enhanced for node type was added: + * <pre> + * Statement: + * Block + * IfStatement + * ForStatement + * EnhancedForStatement + * WhileStatement + * DoStatement + * TryStatement + * SwitchStatement + * SynchronizedStatement + * ReturnStatement + * ThrowStatement + * BreakStatement + * ContinueStatement + * EmptyStatement + * ExpressionStatement + * LabeledStatement + * AssertStatement + * VariableDeclarationStatement + * TypeDeclarationStatement + * ConstructorInvocation + * SuperConstructorInvocation + * </pre> + * </p> + * + * @since 2.0 + */ +public abstract class Statement extends ASTNode { + + /** + * The leading comment, or <code>null</code> if none. + * Defaults to none. + * + * @deprecated The leading comment feature was removed in 2.1. + */ + private String optionalLeadingComment = null; + + /** + * Creates a new AST node for a statement owned by the given AST. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + Statement(AST ast) { + super(ast); + } + + /** + * Returns the leading comment string, including the starting + * and ending comment delimiters, and any embedded line breaks. + * <p> + * A leading comment is a comment that appears before the statement. + * It may be either a traditional comment or an end-of-line comment. + * Traditional comments must begin with "/*, may contain line breaks, + * and must end with "*/. End-of-line comments must begin with "//", + * must end with a line delimiter (as per JLS 3.7), and must not contain + * line breaks. + * </p> + * + * @return the comment string, or <code>null</code> if none + * @deprecated This feature was removed in the 2.1 release because it was + * only a partial, and inadequate, solution to the issue of associating + * comments with statements. Furthermore, AST.parseCompilationUnit did not + * associate leading comments, making this moot. Clients that need to access + * comments preceding a statement should either consult the compilation + * unit's {@linkplain CompilationUnit#getCommentList() comment table} + * or use a scanner to reanalyze the source text immediately preceding + * the statement's source range. + */ + public String getLeadingComment() { + return this.optionalLeadingComment; + } + + /** + * Sets or clears the leading comment string. The comment + * string must include the starting and ending comment delimiters, + * and any embedded linebreaks. + * <p> + * A leading comment is a comment that appears before the statement. + * It may be either a traditional comment or an end-of-line comment. + * Traditional comments must begin with "/*, may contain line breaks, + * and must end with "*/. End-of-line comments must begin with "//" + * (as per JLS 3.7), and must not contain line breaks. + * </p> + * <p> + * Examples: + * <code> + * <pre> + * setLeadingComment("/* traditional comment */"); // correct + * setLeadingComment("missing comment delimiters"); // wrong + * setLeadingComment("/* unterminated traditional comment "); // wrong + * setLeadingComment("/* broken\n traditional comment */"); // correct + * setLeadingComment("// end-of-line comment\n"); // correct + * setLeadingComment("// end-of-line comment without line terminator"); // correct + * setLeadingComment("// broken\n end-of-line comment\n"); // wrong + * </pre> + * </code> + * </p> + * + * @param comment the comment string, or <code>null</code> if none + * @exception IllegalArgumentException if the comment string is invalid + * @deprecated This feature was removed in the 2.1 release because it was + * only a partial, and inadequate, solution to the issue of associating + * comments with statements. + */ + public void setLeadingComment(String comment) { + if (comment != null) { + char[] source = comment.toCharArray(); + Scanner scanner = this.ast.scanner; + scanner.resetTo(0, source.length); + scanner.setSource(source); + try { + int token; + boolean onlyOneComment = false; + while ((token = scanner.getNextToken()) != TerminalTokens.TokenNameEOF) { + switch(token) { + case TerminalTokens.TokenNameCOMMENT_BLOCK : + case TerminalTokens.TokenNameCOMMENT_JAVADOC : + case TerminalTokens.TokenNameCOMMENT_LINE : + if (onlyOneComment) { + throw new IllegalArgumentException(); + } + onlyOneComment = true; + break; + default: + onlyOneComment = false; + } + } + if (!onlyOneComment) { + throw new IllegalArgumentException(); + } + } catch (InvalidInputException e) { + throw new IllegalArgumentException(); + } + } + // we do not consider the obsolete comment as a structureal property + // but we protect them nevertheless + checkModifiable(); + this.optionalLeadingComment = comment; + } + + /** + * Copies the leading comment from the given statement. + * + * @param source the statement that supplies the leading comment + * @since 2.1 + */ + void copyLeadingComment(Statement source) { + setLeadingComment(source.getLeadingComment()); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + int size = BASE_NODE_SIZE + 1 * 4 + stringSize(getLeadingComment()); + return size; + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/StringLiteral.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/StringLiteral.java new file mode 100644 index 000000000..26f55872e --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/StringLiteral.java @@ -0,0 +1,345 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jdt.core.compiler.InvalidInputException; +import org.eclipse.jdt.internal.compiler.parser.Scanner; +import org.eclipse.jdt.internal.compiler.parser.TerminalTokens; + +/** + * String literal nodes. + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class StringLiteral extends Expression { + + /** + * The "escapedValue" structural property of this node type. + * @since 3.0 + */ + public static final SimplePropertyDescriptor ESCAPED_VALUE_PROPERTY = + new SimplePropertyDescriptor(StringLiteral.class, "escapedValue", String.class, MANDATORY); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List propertyList = new ArrayList(2); + createPropertyList(StringLiteral.class, propertyList); + addProperty(ESCAPED_VALUE_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The literal string, including quotes and escapes; defaults to the + * literal for the empty string. + */ + private String escapedValue = "\"\"";//$NON-NLS-1$ + + /** + * Creates a new unparented string literal node owned by the given AST. + * By default, the string literal denotes the empty string. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + StringLiteral(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final Object internalGetSetObjectProperty(SimplePropertyDescriptor property, boolean get, Object value) { + if (property == ESCAPED_VALUE_PROPERTY) { + if (get) { + return getEscapedValue(); + } else { + setEscapedValue((String) value); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetObjectProperty(property, get, value); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return STRING_LITERAL; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + StringLiteral result = new StringLiteral(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setEscapedValue(getEscapedValue()); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + visitor.visit(this); + visitor.endVisit(this); + } + + /** + * Returns the string value of this literal node to the given string + * literal token. The token is the sequence of characters that would appear + * in the source program, including enclosing double quotes and embedded + * escapes. + * + * @return the string literal token, including enclosing double + * quotes and embedded escapes + */ + public String getEscapedValue() { + return this.escapedValue; + } + + /** + * Sets the string value of this literal node to the given string literal + * token. The token is the sequence of characters that would appear in the + * source program, including enclosing double quotes and embedded escapes. + * For example, + * <ul> + * <li><code>""</code> <code>setLiteral("\"\"")</code></li> + * <li><code>"hello world"</code> <code>setLiteral("\"hello world\"")</code></li> + * <li><code>"boo\nhoo"</code> <code>setLiteral("\"boo\\nhoo\"")</code></li> + * </ul> + * + * @param token the string literal token, including enclosing double + * quotes and embedded escapes + * @exception IllegalArgumentException if the argument is incorrect + */ + public void setEscapedValue(String token) { + // update internalSetEscapedValue(String) if this is changed + if (token == null) { + throw new IllegalArgumentException("Token cannot be null"); //$NON-NLS-1$ + } + Scanner scanner = this.ast.scanner; + char[] source = token.toCharArray(); + scanner.setSource(source); + scanner.resetTo(0, source.length); + try { + int tokenType = scanner.getNextToken(); + switch(tokenType) { + case TerminalTokens.TokenNameStringLiteral: + break; + default: + throw new IllegalArgumentException("Invalid string literal : >" + token + "<"); //$NON-NLS-1$//$NON-NLS-2$ + } + } catch(InvalidInputException e) { + throw new IllegalArgumentException("Invalid string literal : >" + token + "<");//$NON-NLS-1$//$NON-NLS-2$ + } + preValueChange(ESCAPED_VALUE_PROPERTY); + this.escapedValue = token; + postValueChange(ESCAPED_VALUE_PROPERTY); + } + + /* (omit javadoc for this method) + * This method is a copy of setEscapedValue(String) that doesn't do any validation. + */ + void internalSetEscapedValue(String token) { + preValueChange(ESCAPED_VALUE_PROPERTY); + this.escapedValue = token; + postValueChange(ESCAPED_VALUE_PROPERTY); + } + + /** + * Returns the value of this literal node. + * <p> + * For example, + * <pre> + * StringLiteral s; + * s.setEscapedValue("\"hello\\nworld\""); + * assert s.getLiteralValue().equals("hello\nworld"); + * </pre> + * </p> + * <p> + * Note that this is a convenience method that converts from the stored + * string literal token returned by <code>getEscapedLiteral</code>. + * </p> + * + * @return the string value without enclosing double quotes and embedded + * escapes + * @exception IllegalArgumentException if the literal value cannot be converted + */ + public String getLiteralValue() { + String s = getEscapedValue(); + int len = s.length(); + if (len < 2 || s.charAt(0) != '\"' || s.charAt(len-1) != '\"' ) { + throw new IllegalArgumentException(); + } + + Scanner scanner = this.ast.scanner; + char[] source = s.toCharArray(); + scanner.setSource(source); + scanner.resetTo(0, source.length); + try { + int tokenType = scanner.getNextToken(); + switch(tokenType) { + case TerminalTokens.TokenNameStringLiteral: + return scanner.getCurrentStringLiteral(); + default: + throw new IllegalArgumentException(); + } + } catch(InvalidInputException e) { + throw new IllegalArgumentException(); + } + } + + /** + * Sets the value of this literal node. + * <p> + * For example, + * <pre> + * StringLiteral s; + * s.setLiteralValue("hello\nworld"); + * assert s.getEscapedValue().equals("\"hello\\nworld\""); + * assert s.getLiteralValue().equals("hello\nworld"); + * </pre> + * </p> + * <p> + * Note that this is a convenience method that converts to the stored + * string literal token acceptable to <code>setEscapedLiteral</code>. + * </p> + * + * @param value the string value without enclosing double quotes and + * embedded escapes + * @exception IllegalArgumentException if the argument is incorrect + */ + public void setLiteralValue(String value) { + if (value == null) { + throw new IllegalArgumentException(); + } + int len = value.length(); + StringBuffer b = new StringBuffer(len + 2); + + b.append("\""); // opening delimiter //$NON-NLS-1$ + for (int i = 0; i < len; i++) { + char c = value.charAt(i); + switch(c) { + case '\b' : + b.append("\\b"); //$NON-NLS-1$ + break; + case '\t' : + b.append("\\t"); //$NON-NLS-1$ + break; + case '\n' : + b.append("\\n"); //$NON-NLS-1$ + break; + case '\f' : + b.append("\\f"); //$NON-NLS-1$ + break; + case '\r' : + b.append("\\r"); //$NON-NLS-1$ + break; + case '\"': + b.append("\\\""); //$NON-NLS-1$ + break; + case '\'': + b.append("\\\'"); //$NON-NLS-1$ + break; + case '\\': + b.append("\\\\"); //$NON-NLS-1$ + break; + case '\0' : + b.append("\\0"); //$NON-NLS-1$ + break; + case '\1' : + b.append("\\1"); //$NON-NLS-1$ + break; + case '\2' : + b.append("\\2"); //$NON-NLS-1$ + break; + case '\3' : + b.append("\\3"); //$NON-NLS-1$ + break; + case '\4' : + b.append("\\4"); //$NON-NLS-1$ + break; + case '\5' : + b.append("\\5"); //$NON-NLS-1$ + break; + case '\6' : + b.append("\\6"); //$NON-NLS-1$ + break; + case '\7' : + b.append("\\7"); //$NON-NLS-1$ + break; + default: + b.append(c); + } + } + b.append("\""); // closing delimiter //$NON-NLS-1$ + setEscapedValue(b.toString()); + } + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + int size = BASE_NODE_SIZE + 1 * 4 + stringSize(this.escapedValue); + return size; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return memSize(); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/StructuralPropertyDescriptor.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/StructuralPropertyDescriptor.java new file mode 100644 index 000000000..ddd178af3 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/StructuralPropertyDescriptor.java @@ -0,0 +1,143 @@ +/******************************************************************************* + * Copyright (c) 2004, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.dom; + +/** + * Abstract base class for property descriptors of AST nodes. + * There are three kinds of properties: + * <ul> + * <li>simple properties ({@link SimplePropertyDescriptor}) + * - properties where the value is a primitive (int, boolean) + * or simple (String, InfixExprsssion.Operator) type other than an + * AST node; for example, the identifier of a {@link SimpleName}</li> + * <li>child properties ({@link ChildPropertyDescriptor}) + * - properties whose value is another AST node; + * for example, the name of a {@link MethodDeclaration}</li> + * <li>child list properties ({@link ChildListPropertyDescriptor}) + * - properties where the value is a list of AST nodes; + * for example, the statements of a {@link Block}</li> + * </ul> + * + * @since 3.0 + * @noextend This class is not intended to be subclassed by clients. + */ +public abstract class StructuralPropertyDescriptor { + + /** + * Property id. + */ + private final String propertyId; + + /** + * The concrete AST node type that owns this property. + */ + private final Class nodeClass; + + /** + * Creates a new property descriptor for the given node type + * with the given property id. + * Note that this constructor is declared package-private so that + * property descriptors can only be created by the AST + * implementation. + * + * @param nodeClass concrete AST node type that owns this property + * @param propertyId the property id + */ + StructuralPropertyDescriptor(Class nodeClass, String propertyId) { + if (nodeClass == null || propertyId == null) { + throw new IllegalArgumentException(); + } + this.propertyId = propertyId; + this.nodeClass = nodeClass; + } + + /** + * Returns the id of this property. + * + * @return the property id + */ + public final String getId() { + return this.propertyId; + } + + /** + * Returns the AST node type that owns this property. + * <p> + * For example, for all properties of the node type + * TypeDeclaration, this method returns <code>TypeDeclaration.class</code>. + * </p> + * + * @return the node type that owns this property + */ + public final Class getNodeClass() { + return this.nodeClass; + } + + /** + * Returns whether this property is a simple property + * (instance of {@link SimplePropertyDescriptor}. + * + * @return <code>true</code> if this is a simple property, and + * <code>false</code> otherwise + */ + public final boolean isSimpleProperty(){ + return (this instanceof SimplePropertyDescriptor); + } + + /** + * Returns whether this property is a child property + * (instance of {@link ChildPropertyDescriptor}. + * + * @return <code>true</code> if this is a child property, and + * <code>false</code> otherwise + */ + public final boolean isChildProperty() { + return (this instanceof ChildPropertyDescriptor); + } + + /** + * Returns whether this property is a child list property + * (instance of {@link ChildListPropertyDescriptor}. + * + * @return <code>true</code> if this is a child list property, and + * <code>false</code> otherwise + */ + public final boolean isChildListProperty() { + return (this instanceof ChildListPropertyDescriptor); + } + + /** + * Returns a string suitable for debug purposes. + * @return {@inheritDoc} + */ + public String toString() { + StringBuffer b = new StringBuffer(); + if (isChildListProperty()) { + b.append("ChildList"); //$NON-NLS-1$ + } + if (isChildProperty()) { + b.append("Child"); //$NON-NLS-1$ + } + if (isSimpleProperty()) { + b.append("Simple"); //$NON-NLS-1$ + } + b.append("Property["); //$NON-NLS-1$ + if (this.nodeClass != null) { + b.append(this.nodeClass.getName()); + } + b.append(","); //$NON-NLS-1$ + if (this.propertyId != null) { + b.append(this.propertyId); + } + b.append("]"); //$NON-NLS-1$ + return b.toString(); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SuperConstructorInvocation.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SuperConstructorInvocation.java new file mode 100644 index 000000000..415798dff --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SuperConstructorInvocation.java @@ -0,0 +1,317 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Super constructor invocation statement AST node type. + * For JLS2: * <pre> + * SuperConstructorInvocation: + * [ Expression <b>.</b> ] <b>super</b> + * <b>(</b> [ Expression { <b>,</b> Expression } ] <b>)</b> <b>;</b> + * </pre> + * For JLS3, type arguments are added: + * <pre> + * SuperConstructorInvocation: + * [ Expression <b>.</b> ] + * [ <b><</b> Type { <b>,</b> Type } <b>></b> ] + * <b>super</b> <b>(</b> [ Expression { <b>,</b> Expression } ] <b>)</b> <b>;</b> + * </pre> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class SuperConstructorInvocation extends Statement { + + /** + * The "expression" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor EXPRESSION_PROPERTY = + new ChildPropertyDescriptor(SuperConstructorInvocation.class, "expression", Expression.class, OPTIONAL, CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "typeArguments" structural property of this node type (added in JLS3 API). + * @since 3.1 + */ + public static final ChildListPropertyDescriptor TYPE_ARGUMENTS_PROPERTY = + new ChildListPropertyDescriptor(SuperConstructorInvocation.class, "typeArguments", Type.class, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "arguments" structural property of this node type. + * @since 3.0 + */ + public static final ChildListPropertyDescriptor ARGUMENTS_PROPERTY = + new ChildListPropertyDescriptor(SuperConstructorInvocation.class, "arguments", Expression.class, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + * @since 3.0 + */ + private static final List PROPERTY_DESCRIPTORS_2_0; + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + * @since 3.1 + */ + private static final List PROPERTY_DESCRIPTORS_3_0; + + static { + List propertyList = new ArrayList(3); + createPropertyList(SuperConstructorInvocation.class, propertyList); + addProperty(EXPRESSION_PROPERTY, propertyList); + addProperty(ARGUMENTS_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS_2_0 = reapPropertyList(propertyList); + + propertyList = new ArrayList(4); + createPropertyList(SuperConstructorInvocation.class, propertyList); + addProperty(EXPRESSION_PROPERTY, propertyList); + addProperty(TYPE_ARGUMENTS_PROPERTY, propertyList); + addProperty(ARGUMENTS_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS_3_0 = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + if (apiLevel == AST.JLS2_INTERNAL) { + return PROPERTY_DESCRIPTORS_2_0; + } else { + return PROPERTY_DESCRIPTORS_3_0; + } + } + + /** + * The expression; <code>null</code> for none; defaults to none. + */ + private Expression optionalExpression = null; + + /** + * The type arguments (element type: <code>Type</code>). + * Null in JLS2. Added in JLS3; defaults to an empty list + * (see constructor). + * @since 3.1 + */ + private ASTNode.NodeList typeArguments = null; + + /** + * The list of argument expressions (element type: + * <code>Expression</code>). Defaults to an empty list. + */ + private ASTNode.NodeList arguments = + new ASTNode.NodeList(ARGUMENTS_PROPERTY); + + /** + * Creates a new AST node for an super constructor invocation statement + * owned by the given AST. By default, no type arguments, and an empty list + * of arguments. + * + * @param ast the AST that is to own this node + */ + SuperConstructorInvocation(AST ast) { + super(ast); + if (ast.apiLevel >= AST.JLS3) { + this.typeArguments = new ASTNode.NodeList(TYPE_ARGUMENTS_PROPERTY); + } + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == EXPRESSION_PROPERTY) { + if (get) { + return getExpression(); + } else { + setExpression((Expression) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalGetChildListProperty(ChildListPropertyDescriptor property) { + if (property == ARGUMENTS_PROPERTY) { + return arguments(); + } + if (property == TYPE_ARGUMENTS_PROPERTY) { + return typeArguments(); + } + // allow default implementation to flag the error + return super.internalGetChildListProperty(property); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return SUPER_CONSTRUCTOR_INVOCATION; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + SuperConstructorInvocation result = new SuperConstructorInvocation(target); + result.setSourceRange(getStartPosition(), getLength()); + result.copyLeadingComment(this); + result.setExpression( + (Expression) ASTNode.copySubtree(target, getExpression())); + if (this.ast.apiLevel >= AST.JLS3) { + result.typeArguments().addAll(ASTNode.copySubtrees(target, typeArguments())); + } + result.arguments().addAll(ASTNode.copySubtrees(target, arguments())); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + acceptChild(visitor, getExpression()); + if (this.ast.apiLevel >= AST.JLS3) { + acceptChildren(visitor, this.typeArguments); + } + acceptChildren(visitor, this.arguments); + } + visitor.endVisit(this); + } + + /** + * Returns the expression of this super constructor invocation statement, + * or <code>null</code> if there is none. + * + * @return the expression node, or <code>null</code> if there is none + */ + public Expression getExpression() { + return this.optionalExpression; + } + + /** + * Sets or clears the expression of this super constructor invocation + * statement. + * + * @param expression the expression node, or <code>null</code> if + * there is none + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setExpression(Expression expression) { + ASTNode oldChild = this.optionalExpression; + preReplaceChild(oldChild, expression, EXPRESSION_PROPERTY); + this.optionalExpression = expression; + postReplaceChild(oldChild, expression, EXPRESSION_PROPERTY); + } + + /** + * Returns the live ordered list of type arguments of this constructor + * invocation (added in JLS3 API). + * + * @return the live list of type arguments + * (element type: <code>Type</code>) + * @exception UnsupportedOperationException if this operation is used in + * a JLS2 AST + * @since 3.1 + */ + public List typeArguments() { + // more efficient than just calling unsupportedIn2() to check + if (this.typeArguments == null) { + unsupportedIn2(); + } + return this.typeArguments; + } + + /** + * Returns the live ordered list of argument expressions in this super + * constructor invocation statement. + * + * @return the live list of argument expressions + * (element type: <code>Expression</code>) + */ + public List arguments() { + return this.arguments; + } + + /** + * Resolves and returns the binding for the constructor invoked by this + * expression. + * <p> + * Note that bindings are generally unavailable unless requested when the + * AST is being built. + * </p> + * + * @return the constructor binding, or <code>null</code> if the binding + * cannot be resolved + */ + public IMethodBinding resolveConstructorBinding() { + return this.ast.getBindingResolver().resolveConstructor(this); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + // treat Code as free + return BASE_NODE_SIZE + 3 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return memSize() + + (this.optionalExpression == null ? 0 : getExpression().treeSize()) + + (this.typeArguments == null ? 0 : this.typeArguments.listSize()) + + (this.arguments == null ? 0 : this.arguments.listSize()); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SuperFieldAccess.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SuperFieldAccess.java new file mode 100644 index 000000000..a20c01fab --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SuperFieldAccess.java @@ -0,0 +1,277 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Simple or qualified "super" field access expression AST node type. + * + * <pre> + * SuperFieldAccess: + * [ ClassName <b>.</b> ] <b>super</b> <b>.</b> Identifier + * </pre> + * + * <p> + * See <code>FieldAccess</code> for guidelines on handling other expressions + * that resemble qualified names. + * </p> + * + * @see FieldAccess + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class SuperFieldAccess extends Expression { + + /** + * The "qualifier" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor QUALIFIER_PROPERTY = + new ChildPropertyDescriptor(SuperFieldAccess.class, "qualifier", Name.class, OPTIONAL, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "name" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor NAME_PROPERTY = + new ChildPropertyDescriptor(SuperFieldAccess.class, "name", SimpleName.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List propertyList = new ArrayList(3); + createPropertyList(SuperFieldAccess.class, propertyList); + addProperty(QUALIFIER_PROPERTY, propertyList); + addProperty(NAME_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The optional qualifier; <code>null</code> for none; defaults to none. + */ + private Name optionalQualifier = null; + + /** + * The field; lazily initialized; defaults to an unspecified, + * but legal, simple field name. + */ + private SimpleName fieldName = null; + + /** + * Creates a new unparented node for a super field access expression owned + * by the given AST. By default, field name is an unspecified, but legal, + * name, and there is no qualifier. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + SuperFieldAccess(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == QUALIFIER_PROPERTY) { + if (get) { + return getQualifier(); + } else { + setQualifier((Name) child); + return null; + } + } + if (property == NAME_PROPERTY) { + if (get) { + return getName(); + } else { + setName((SimpleName) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return SUPER_FIELD_ACCESS; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + SuperFieldAccess result = new SuperFieldAccess(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setName((SimpleName) ASTNode.copySubtree(target, getName())); + result.setQualifier((Name) ASTNode.copySubtree(target, getQualifier())); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + acceptChild(visitor, getQualifier()); + acceptChild(visitor, getName()); + } + visitor.endVisit(this); + } + + /** + * Returns the qualifier of this "super" field access expression, or + * <code>null</code> if there is none. + * + * @return the qualifier name node, or <code>null</code> if there is none + */ + public Name getQualifier() { + return this.optionalQualifier; + } + + /** + * Sets or clears the qualifier of this "super" field access expression. + * + * @param name the qualifier name node, or <code>null</code> if + * there is none + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public void setQualifier(Name name) { + ASTNode oldChild = this.optionalQualifier; + preReplaceChild(oldChild, name, QUALIFIER_PROPERTY); + this.optionalQualifier = name; + postReplaceChild(oldChild, name, QUALIFIER_PROPERTY); + } + + /** + * Returns the name of the field accessed in this "super" field access + * expression. + * + * @return the field name + */ + public SimpleName getName() { + if (this.fieldName == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.fieldName == null) { + preLazyInit(); + this.fieldName = new SimpleName(this.ast); + postLazyInit(this.fieldName, NAME_PROPERTY); + } + } + } + return this.fieldName; + } + + /** + * Resolves and returns the binding for the field accessed by this + * expression. + * <p> + * Note that bindings are generally unavailable unless requested when the + * AST is being built. + * </p> + * + * @return the variable binding, or <code>null</code> if the binding cannot + * be resolved + * @since 3.0 + */ + public IVariableBinding resolveFieldBinding() { + return this.ast.getBindingResolver().resolveField(this); + } + + /** + * Sets the name of the field accessed in this "super" field access + * expression. + * + * @param fieldName the field name + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public void setName(SimpleName fieldName) { + if (fieldName == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.fieldName; + preReplaceChild(oldChild, fieldName, NAME_PROPERTY); + this.fieldName = fieldName; + postReplaceChild(oldChild, fieldName, NAME_PROPERTY); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + // treat Code as free + return BASE_NODE_SIZE + 2 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.optionalQualifier == null ? 0 : getQualifier().treeSize()) + + (this.fieldName == null ? 0 : getName().treeSize()); + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SuperMethodInvocation.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SuperMethodInvocation.java new file mode 100644 index 000000000..bd61dbfb9 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SuperMethodInvocation.java @@ -0,0 +1,397 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Simple or qualified "super" method invocation expression AST node type. + * For JLS2: + * <pre> + * SuperMethodInvocation: + * [ ClassName <b>.</b> ] <b>super</b> <b>.</b> Identifier + * <b>(</b> [ Expression { <b>,</b> Expression } ] <b>)</b> + * </pre> + * For JLS3, type arguments are added: + * <pre> + * SuperMethodInvocation: + * [ ClassName <b>.</b> ] <b>super</b> <b>.</b> + * [ <b><</b> Type { <b>,</b> Type } <b>></b> ] + * Identifier <b>(</b> [ Expression { <b>,</b> Expression } ] <b>)</b> + * </pre> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class SuperMethodInvocation extends Expression { + + /** + * The "qualifier" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor QUALIFIER_PROPERTY = + new ChildPropertyDescriptor(SuperMethodInvocation.class, "qualifier", Name.class, OPTIONAL, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "typeArguments" structural property of this node type (added in JLS3 API). + * @since 3.1 + */ + public static final ChildListPropertyDescriptor TYPE_ARGUMENTS_PROPERTY = + new ChildListPropertyDescriptor(SuperMethodInvocation.class, "typeArguments", Type.class, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "name" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor NAME_PROPERTY = + new ChildPropertyDescriptor(SuperMethodInvocation.class, "name", SimpleName.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "arguments" structural property of this node type. + * @since 3.0 + */ + public static final ChildListPropertyDescriptor ARGUMENTS_PROPERTY = + new ChildListPropertyDescriptor(SuperMethodInvocation.class, "arguments", Expression.class, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + * @since 3.0 + */ + private static final List PROPERTY_DESCRIPTORS_2_0; + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + * @since 3.1 + */ + private static final List PROPERTY_DESCRIPTORS_3_0; + + static { + List propertyList = new ArrayList(4); + createPropertyList(SuperMethodInvocation.class, propertyList); + addProperty(QUALIFIER_PROPERTY, propertyList); + addProperty(NAME_PROPERTY, propertyList); + addProperty(ARGUMENTS_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS_2_0 = reapPropertyList(propertyList); + + propertyList = new ArrayList(5); + createPropertyList(SuperMethodInvocation.class, propertyList); + addProperty(QUALIFIER_PROPERTY, propertyList); + addProperty(TYPE_ARGUMENTS_PROPERTY, propertyList); + addProperty(NAME_PROPERTY, propertyList); + addProperty(ARGUMENTS_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS_3_0 = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + if (apiLevel == AST.JLS2_INTERNAL) { + return PROPERTY_DESCRIPTORS_2_0; + } else { + return PROPERTY_DESCRIPTORS_3_0; + } + } + + /** + * The optional qualifier; <code>null</code> for none; defaults to none. + */ + private Name optionalQualifier = null; + + /** + * The type arguments (element type: <code>Type</code>). + * Null in JLS2. Added in JLS3; defaults to an empty list + * (see constructor). + * @since 3.1 + */ + private ASTNode.NodeList typeArguments = null; + + /** + * The method name; lazily initialized; defaults to a unspecified, + * legal Java method name. + */ + private SimpleName methodName = null; + + /** + * The list of argument expressions (element type: + * <code>Expression</code>). Defaults to an empty list. + */ + private ASTNode.NodeList arguments = + new ASTNode.NodeList(ARGUMENTS_PROPERTY); + + /** + * Creates a new AST node for a "super" method invocation expression owned + * by the given AST. By default, no qualifier, no type arguments, + * an unspecified, but legal, method name, and an empty list of arguments. + * + * @param ast the AST that is to own this node + */ + SuperMethodInvocation(AST ast) { + super(ast); + if (ast.apiLevel >= AST.JLS3) { + this.typeArguments = new ASTNode.NodeList(TYPE_ARGUMENTS_PROPERTY); + } + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == QUALIFIER_PROPERTY) { + if (get) { + return getQualifier(); + } else { + setQualifier((Name) child); + return null; + } + } + if (property == NAME_PROPERTY) { + if (get) { + return getName(); + } else { + setName((SimpleName) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalGetChildListProperty(ChildListPropertyDescriptor property) { + if (property == ARGUMENTS_PROPERTY) { + return arguments(); + } + if (property == TYPE_ARGUMENTS_PROPERTY) { + return typeArguments(); + } + // allow default implementation to flag the error + return super.internalGetChildListProperty(property); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return SUPER_METHOD_INVOCATION; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + SuperMethodInvocation result = new SuperMethodInvocation(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setName((SimpleName) getName().clone(target)); + result.setQualifier((Name) ASTNode.copySubtree(target, getQualifier())); + if (this.ast.apiLevel >= AST.JLS3) { + result.typeArguments().addAll(ASTNode.copySubtrees(target, typeArguments())); + } + result.arguments().addAll(ASTNode.copySubtrees(target, arguments())); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + acceptChild(visitor, getQualifier()); + if (this.ast.apiLevel >= AST.JLS3) { + acceptChildren(visitor, this.typeArguments); + } + acceptChild(visitor, getName()); + acceptChildren(visitor, this.arguments); + } + visitor.endVisit(this); + } + + /** + * Returns the qualifier of this "super" method invocation expression, or + * <code>null</code> if there is none. + * + * @return the qualifier name node, or <code>null</code> if there is none + */ + public Name getQualifier() { + return this.optionalQualifier; + } + + /** + * Returns true if the resolved return type has been inferred from the assignment context (JLS3 15.12.2.8), false otherwise. + * <p> + * This information is available only when bindings are requested when the AST is being built + * </p>. + * + * @return true if the resolved return type has been inferred from the assignment context (JLS3 15.12.2.8), false otherwise + * @since 3.3 + */ + public boolean isResolvedTypeInferredFromExpectedType() { + return this.ast.getBindingResolver().isResolvedTypeInferredFromExpectedType(this); + } + + + /** + * Sets or clears the qualifier of this "super" method invocation expression. + * + * @param name the qualifier name node, or <code>null</code> if + * there is none + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public void setQualifier(Name name) { + ASTNode oldChild = this.optionalQualifier; + preReplaceChild(oldChild, name, QUALIFIER_PROPERTY); + this.optionalQualifier = name; + postReplaceChild(oldChild, name, QUALIFIER_PROPERTY); + } + + /** + * Returns the live ordered list of type arguments of this method + * invocation (added in JLS3 API). + * + * @return the live list of type arguments + * (element type: <code>Type</code>) + * @exception UnsupportedOperationException if this operation is used in + * a JLS2 AST + * @since 3.1 + */ + public List typeArguments() { + // more efficient than just calling unsupportedIn2() to check + if (this.typeArguments == null) { + unsupportedIn2(); + } + return this.typeArguments; + } + + /** + * Returns the name of the method invoked in this expression. + * + * @return the method name node + */ + public SimpleName getName() { + if (this.methodName == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.methodName == null) { + preLazyInit(); + this.methodName = new SimpleName(this.ast); + postLazyInit(this.methodName, NAME_PROPERTY); + } + } + } + return this.methodName; + } + + /** + * Sets the name of the method invoked in this expression to the + * given name. + * + * @param name the new method name + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public void setName(SimpleName name) { + if (name == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.methodName; + preReplaceChild(oldChild, name, NAME_PROPERTY); + this.methodName = name; + postReplaceChild(oldChild, name, NAME_PROPERTY); + } + + /** + * Returns the live ordered list of argument expressions in this + * "super" method invocation expression. + * + * @return the live list of argument expressions + * (element type: <code>Expression</code>) + */ + public List arguments() { + return this.arguments; + } + + /** + * Resolves and returns the binding for the method invoked by this + * expression. + * <p> + * Note that bindings are generally unavailable unless requested when the + * AST is being built. + * </p> + * + * @return the method binding, or <code>null</code> if the binding cannot + * be resolved + * @since 2.1 + */ + public IMethodBinding resolveMethodBinding() { + return this.ast.getBindingResolver().resolveMethod(this); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + // treat Code as free + return BASE_NODE_SIZE + 4 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.optionalQualifier == null ? 0 : getQualifier().treeSize()) + + (this.typeArguments == null ? 0 : this.typeArguments.listSize()) + + (this.methodName == null ? 0 : getName().treeSize()) + + (this.arguments == null ? 0 : this.arguments.listSize()); + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SwitchCase.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SwitchCase.java new file mode 100644 index 000000000..b28fbe85c --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SwitchCase.java @@ -0,0 +1,222 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Switch case AST node type. A switch case is a special kind of node used only + * in switch statements. It is a <code>Statement</code> in name only. + * <p> + * <pre> + * SwitchCase: + * <b>case</b> Expression <b>:</b> + * <b>default</b> <b>:</b> + * </pre> + * </p> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class SwitchCase extends Statement { + + /** + * The "expression" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor EXPRESSION_PROPERTY = + new ChildPropertyDescriptor(SwitchCase.class, "expression", Expression.class, OPTIONAL, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List propertyList = new ArrayList(2); + createPropertyList(SwitchCase.class, propertyList); + addProperty(EXPRESSION_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The expression; <code>null</code> for none; lazily initialized (but + * does <b>not</b> default to none). + * @see #expressionInitialized + */ + private Expression optionalExpression = null; + + /** + * Indicates whether <code>optionalExpression</code> has been initialized. + */ + private boolean expressionInitialized = false; + + /** + * Creates a new AST node for a switch case pseudo-statement owned by the + * given AST. By default, there is an unspecified, but legal, expression. + * + * @param ast the AST that is to own this node + */ + SwitchCase(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == EXPRESSION_PROPERTY) { + if (get) { + return getExpression(); + } else { + setExpression((Expression) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return SWITCH_CASE; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + SwitchCase result = new SwitchCase(target); + result.setSourceRange(getStartPosition(), getLength()); + result.copyLeadingComment(this); + result.setExpression( + (Expression) ASTNode.copySubtree(target, getExpression())); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + acceptChild(visitor, getExpression()); + } + visitor.endVisit(this); + } + + /** + * Returns the expression of this switch case, or + * <code>null</code> if there is none (the "default:" case). + * + * @return the expression node, or <code>null</code> if there is none + */ + public Expression getExpression() { + if (!this.expressionInitialized) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (!this.expressionInitialized) { + preLazyInit(); + this.optionalExpression = new SimpleName(this.ast); + this.expressionInitialized = true; + postLazyInit(this.optionalExpression, EXPRESSION_PROPERTY); + } + } + } + return this.optionalExpression; + } + + /** + * Sets the expression of this switch case, or clears it (turns it into + * the "default:" case). + * + * @param expression the expression node, or <code>null</code> to + * turn it into the "default:" case + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setExpression(Expression expression) { + ASTNode oldChild = this.optionalExpression; + preReplaceChild(oldChild, expression, EXPRESSION_PROPERTY); + this.optionalExpression = expression; + this.expressionInitialized = true; + postReplaceChild(oldChild, expression, EXPRESSION_PROPERTY); + } + + /** + * Returns whether this switch case represents the "default:" case. + * <p> + * This convenience method is equivalent to + * <code>getExpression() == null</code>. + * </p> + * + * @return <code>true</code> if this is the default switch case, and + * <code>false</code> if this is a non-default switch case + */ + public boolean isDefault() { + return getExpression() == null; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return super.memSize() + 2 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.optionalExpression == null ? 0 : this.optionalExpression.treeSize()); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SwitchStatement.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SwitchStatement.java new file mode 100644 index 000000000..f8c51a596 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SwitchStatement.java @@ -0,0 +1,250 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Switch statement AST node type. + * <p> + * <pre> + * SwitchStatement: + * <b>switch</b> <b>(</b> Expression <b>)</b> + * <b>{</b> { SwitchCase | Statement } } <b>}</b> + * SwitchCase: + * <b>case</b> Expression <b>:</b> + * <b>default</b> <b>:</b> + * </pre> + * <code>SwitchCase</code> nodes are treated as a kind of + * <code>Statement</code>. + * </p> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class SwitchStatement extends Statement { + + /** + * The "expression" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor EXPRESSION_PROPERTY = + new ChildPropertyDescriptor(SwitchStatement.class, "expression", Expression.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "statements" structural property of this node type. + * @since 3.0 + */ + public static final ChildListPropertyDescriptor STATEMENTS_PROPERTY = + new ChildListPropertyDescriptor(SwitchStatement.class, "statements", Statement.class, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List propertyList = new ArrayList(3); + createPropertyList(SwitchStatement.class, propertyList); + addProperty(EXPRESSION_PROPERTY, propertyList); + addProperty(STATEMENTS_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The expression; lazily initialized; defaults to a unspecified, but legal, + * expression. + */ + private Expression expression = null; + + /** + * The statements and SwitchCase nodes + * (element type: <code>Statement</code>). + * Defaults to an empty list. + */ + private ASTNode.NodeList statements = + new ASTNode.NodeList(STATEMENTS_PROPERTY); + + /** + * Creates a new unparented switch statement node owned by the given + * AST. By default, the swicth statement has an unspecified, but legal, + * expression, and an empty list of switch groups. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + SwitchStatement(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == EXPRESSION_PROPERTY) { + if (get) { + return getExpression(); + } else { + setExpression((Expression) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalGetChildListProperty(ChildListPropertyDescriptor property) { + if (property == STATEMENTS_PROPERTY) { + return statements(); + } + // allow default implementation to flag the error + return super.internalGetChildListProperty(property); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return SWITCH_STATEMENT; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + SwitchStatement result = new SwitchStatement(target); + result.setSourceRange(getStartPosition(), getLength()); + result.copyLeadingComment(this); + result.setExpression((Expression) getExpression().clone(target)); + result.statements().addAll(ASTNode.copySubtrees(target, statements())); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + acceptChild(visitor, getExpression()); + acceptChildren(visitor, this.statements); + } + visitor.endVisit(this); + } + + /** + * Returns the expression of this switch statement. + * + * @return the expression node + */ + public Expression getExpression() { + if (this.expression == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.expression == null) { + preLazyInit(); + this.expression = new SimpleName(this.ast); + postLazyInit(this.expression, EXPRESSION_PROPERTY); + } + } + } + return this.expression; + } + + /** + * Sets the expression of this switch statement. + * + * @param expression the new expression node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setExpression(Expression expression) { + if (expression == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.expression; + preReplaceChild(oldChild, expression, EXPRESSION_PROPERTY); + this.expression = expression; + postReplaceChild(oldChild, expression, EXPRESSION_PROPERTY); + } + + /** + * Returns the live ordered list of statements for this switch statement. + * Within this list, <code>SwitchCase</code> nodes mark the start of + * the switch groups. + * + * @return the live list of statement nodes + * (element type: <code>Statement</code>) + */ + public List statements() { + return this.statements; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return super.memSize() + 2 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.expression == null ? 0 : getExpression().treeSize()) + + this.statements.listSize(); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SynchronizedStatement.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SynchronizedStatement.java new file mode 100644 index 000000000..4fbf63f40 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SynchronizedStatement.java @@ -0,0 +1,266 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Synchronized statement AST node type. + * + * <pre> + * SynchronizedStatement: + * <b>synchronized</b> <b>(</b> Expression <b>)</b> Block + * </pre> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class SynchronizedStatement extends Statement { + + /** + * The "expression" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor EXPRESSION_PROPERTY = + new ChildPropertyDescriptor(SynchronizedStatement.class, "expression", Expression.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "body" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor BODY_PROPERTY = + new ChildPropertyDescriptor(SynchronizedStatement.class, "body", Block.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List propertyList = new ArrayList(3); + createPropertyList(SynchronizedStatement.class, propertyList); + addProperty(EXPRESSION_PROPERTY, propertyList); + addProperty(BODY_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The expression; lazily initialized; defaults to an unspecified, but + * legal, expression. + */ + private Expression expression = null; + + /** + * The body; lazily initialized; defaults to an empty block. + */ + private Block body = null; + + /** + * Creates a new unparented synchronized statement node owned by the given + * AST. By default, the expression is unspecified, but legal, and the + * blody is an empty block. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + SynchronizedStatement(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == EXPRESSION_PROPERTY) { + if (get) { + return getExpression(); + } else { + setExpression((Expression) child); + return null; + } + } + if (property == BODY_PROPERTY) { + if (get) { + return getBody(); + } else { + setBody((Block) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return SYNCHRONIZED_STATEMENT; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + SynchronizedStatement result = new SynchronizedStatement(target); + result.setSourceRange(getStartPosition(), getLength()); + result.copyLeadingComment(this); + result.setExpression((Expression) getExpression().clone(target)); + result.setBody((Block) getBody().clone(target)); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + acceptChild(visitor, getExpression()); + acceptChild(visitor, getBody()); + } + visitor.endVisit(this); + } + + /** + * Returns the expression of this synchronized statement. + * + * @return the expression node + */ + public Expression getExpression() { + if (this.expression == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.expression == null) { + preLazyInit(); + this.expression = new SimpleName(this.ast); + postLazyInit(this.expression, EXPRESSION_PROPERTY); + } + } + } + return this.expression; + } + + /** + * Sets the expression of this synchronized statement. + * + * @param expression the expression node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setExpression(Expression expression) { + if (expression == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.expression; + preReplaceChild(oldChild, expression, EXPRESSION_PROPERTY); + this.expression = expression; + postReplaceChild(oldChild, expression, EXPRESSION_PROPERTY); + } + + /** + * Returns the body of this synchronized statement. + * + * @return the body block node + */ + public Block getBody() { + if (this.body == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.body == null) { + preLazyInit(); + this.body = new Block(this.ast); + postLazyInit(this.body, BODY_PROPERTY); + } + } + } + return this.body; + } + + /** + * Sets the body of this synchronized statement. + * + * @param block the body statement node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setBody(Block block) { + if (block == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.body; + preReplaceChild(oldChild, block, BODY_PROPERTY); + this.body = block; + postReplaceChild(oldChild, block, BODY_PROPERTY); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return super.memSize() + 2 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.expression == null ? 0 : getExpression().treeSize()) + + (this.body == null ? 0 : getBody().treeSize()); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TSuperConstructorInvocation.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TSuperConstructorInvocation.java new file mode 100644 index 000000000..50e877b84 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TSuperConstructorInvocation.java @@ -0,0 +1,185 @@ +/********************************************************************** + * This file is part of "Object Teams Development Tooling"-Software + * + * Copyright 2004, 2006 Fraunhofer Gesellschaft, Munich, Germany, + * for its Fraunhofer Institute for Computer Architecture and Software + * Technology (FIRST), Berlin, Germany and Technical University Berlin, + * Germany. + * + * 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 + * $Id: TSuperConstructorInvocation.java 23416 2010-02-03 19:59:31Z stephan $ + * + * Please visit http://www.eclipse.org/objectteams for updates and contact. + * + * Contributors: + * Fraunhofer FIRST - Initial API and implementation + * Technical University Berlin - Initial API and implementation + **********************************************************************/ +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * NEW for OTDT. + * + * TSuperConstructorInvocation represents a 'tsuper call' to a constructor + * of the role's implicit super role-class (OTJLD §2.4.2), + * e.g. <code>tsuper();</code> or <code>tsuper(arg0, arg1);</code>. + * + * Contained AST elements: + * a list of argument expressions (<code>Expression</code>). + * + * Locations in source code: + * This node can only be used inside bodies of a role constructor, + * it appears in <code>Block</code>s only. + * + * @author mkr + */ +public class TSuperConstructorInvocation extends Statement +{ + /** + * The "arguments" structural property of this node type. + * @since 3.0 + */ + public static final ChildListPropertyDescriptor ARGUMENTS_PROPERTY = + new ChildListPropertyDescriptor(TSuperConstructorInvocation.class, "arguments", Expression.class, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + * @since 3.0 + */ + @SuppressWarnings("rawtypes") + private static final List PROPERTY_DESCRIPTORS; + + + static { + ArrayList<StructuralPropertyDescriptor> propertyList = new ArrayList<StructuralPropertyDescriptor>(2); + createPropertyList(TSuperConstructorInvocation.class, propertyList); + addProperty(ARGUMENTS_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + @SuppressWarnings("rawtypes") + public static List propertyDescriptors(int apiLevel) + { + return PROPERTY_DESCRIPTORS; + } + + /** + * The list of argument expressions (element type: + * <code>Expression</code>). Defaults to an empty list. + */ + private ASTNode.NodeList arguments = + new ASTNode.NodeList(ARGUMENTS_PROPERTY); + + /** + * Creates a new AST node for an tsuper constructor invocation statement + * owned by the given AST. By default, no type arguments, and an empty list + * of arguments. + * + * @param ast the AST that is to own this node + */ + TSuperConstructorInvocation(AST ast) + { + super(ast); + } + + /** + * Returns the live ordered list of argument expressions in this + * base constructor invocation expression. + * + * @return the live list of argument expressions + * (element type: <code>Expression</code>) + */ + @SuppressWarnings("rawtypes") + public List getArguments() + { + return this.arguments; + } + + @SuppressWarnings("rawtypes") + final List internalStructuralPropertiesForType(int apiLevel) + { + return propertyDescriptors(apiLevel); + } + + @SuppressWarnings("rawtypes") + final List internalGetChildListProperty(ChildListPropertyDescriptor property) + { + if (property == ARGUMENTS_PROPERTY) + { + return getArguments(); + } + + // allow default implementation to flag the error + return super.internalGetChildListProperty(property); + } + + final int getNodeType0() + { + return TSUPER_CONSTRUCTOR_INVOCATION; + } + + @SuppressWarnings("unchecked") + ASTNode clone0(AST target) + { + TSuperConstructorInvocation result = new TSuperConstructorInvocation(target); + result.setSourceRange(this.getStartPosition(), this.getLength()); + result.getArguments().addAll(ASTNode.copySubtrees(target, getArguments())); + + return result; + } + + final boolean subtreeMatch0(ASTMatcher matcher, Object other) + { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + void accept0(ASTVisitor visitor) + { + boolean visitChildren = visitor.visit(this); + + if (visitChildren) + { + // visit children in normal left to right reading order + acceptChildren(visitor, this.arguments); + } + visitor.endVisit(this); + } + + int memSize() + { + // treat Operator as free + return BASE_NODE_SIZE + 1 * 4; + } + + int treeSize() + { + return memSize() + (this.arguments == null + ? 0 + : this.arguments.listSize()); + } + + public IMethodBinding resolveConstructorBinding() { + return this.ast.getBindingResolver().resolveConstructor(this); + } + +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TSuperMessageSend.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TSuperMessageSend.java new file mode 100644 index 000000000..1546865e4 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TSuperMessageSend.java @@ -0,0 +1,335 @@ +/********************************************************************** + * This file is part of "Object Teams Development Tooling"-Software + * + * Copyright 2004, 2006 Fraunhofer Gesellschaft, Munich, Germany, + * for its Fraunhofer Institute for Computer Architecture and Software + * Technology (FIRST), Berlin, Germany and Technical University Berlin, + * Germany. + * + * 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 + * $Id: TSuperMessageSend.java 23416 2010-02-03 19:59:31Z stephan $ + * + * Please visit http://www.eclipse.org/objectteams for updates and contact. + * + * Contributors: + * Fraunhofer FIRST - Initial API and implementation + * Technical University Berlin - Initial API and implementation + **********************************************************************/ +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * NEW for OTDT. + * + * TSuperMessageSend represents a super call along the implicit + * inheritance of roles (OTJLD §1.3.1(f)), + * e.g. <code>tsuper.m(arg1, arg2)</code> (only inside method <code>m</code> of a role method) + * or <code>tsuper(arg1, arg2)</code> (only in a constructor of a role class). + * + * Contained AST elements: + * a selector name (<code>SimpleName</code>), e.g. <code>myRoleMethod</code>. + * a List of argument expressions (<code>Expression</code>). + * + * Locations in source code: + * This node can only be used within role methods. + * + * @author mkr + */ +public class TSuperMessageSend extends Expression +{ + /** + * The "name" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor NAME_PROPERTY = + new ChildPropertyDescriptor(TSuperMessageSend.class, + "name",//$NON-NLS-1$ + SimpleName.class, + MANDATORY, + NO_CYCLE_RISK); + + /** + * The "arguments" structural property of this node type. + * @since 3.0 + */ + public static final ChildListPropertyDescriptor ARGUMENTS_PROPERTY = + new ChildListPropertyDescriptor(TSuperMessageSend.class, + "arguments",//$NON-NLS-1$ + Expression.class, + CYCLE_RISK); + + /** + * The "qualifier" structural property of this node type. + */ + public static final ChildPropertyDescriptor QUALIFIER_PROPERTY = + new ChildPropertyDescriptor(TSuperMessageSend.class, + "qualifier", //$NON-NLS-1$ + Name.class, + OPTIONAL, NO_CYCLE_RISK); + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + @SuppressWarnings("rawtypes") + private static final List PROPERTY_DESCRIPTORS; + + static + { + ArrayList<StructuralPropertyDescriptor> propertyList = new ArrayList<StructuralPropertyDescriptor>(4); + createPropertyList(TSuperMessageSend.class, propertyList); + addProperty(NAME_PROPERTY, propertyList); + addProperty(ARGUMENTS_PROPERTY, propertyList); + addProperty(QUALIFIER_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + */ + @SuppressWarnings("rawtypes") + public static List propertyDescriptors(int apiLevel) + { + return PROPERTY_DESCRIPTORS; + } + + /** + * The method name; lazily initialized; + */ + private SimpleName methodName = null; + + /** + * The list of argument expressions (element type: + * <code>Expression</code>). Defaults to an empty list. + */ + private ASTNode.NodeList arguments = + new ASTNode.NodeList(ARGUMENTS_PROPERTY); + + /** + * The tsuper-qualification; lazily initialized; + */ + private Name optionalQualification = null; + + /** + * Creates a new AST node for a tsuper expression owned by the given AST. + * By default, there is no qualifier. + * + * @param ast the AST that is to own this node + */ + TSuperMessageSend(AST ast) + { + super(ast); + } + + @SuppressWarnings("rawtypes") + final List internalStructuralPropertiesForType(int apiLevel) + { + return propertyDescriptors(apiLevel); + } + + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, + boolean get, + ASTNode child) + { + if (property == NAME_PROPERTY) + { + if (get) { + return getName(); + } + else + { + setName((SimpleName) child); + return null; + } + } else + if (property == QUALIFIER_PROPERTY) + { + if (get) { + return getQualifier(); + } + else + { + setQualification((SimpleName) child); + return null; + } + } + + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + @SuppressWarnings("rawtypes") + final List internalGetChildListProperty(ChildListPropertyDescriptor property) + { + if (property == ARGUMENTS_PROPERTY) + { + return getArguments(); + } + + // allow default implementation to flag the error + return super.internalGetChildListProperty(property); + } + + final int getNodeType0() + { + return TSUPER_MESSAGE_SEND; + } + + @SuppressWarnings("unchecked") + ASTNode clone0(AST target) + { + TSuperMessageSend result = new TSuperMessageSend(target); + result.setSourceRange(this.getStartPosition(), this.getLength()); + result.setName((SimpleName)this.methodName.clone(target)); + result.getArguments().addAll(ASTNode.copySubtrees(target, this.arguments)); + result.setQualification((Name)this.optionalQualification.clone(target)); + return result; + } + + /** + * Returns the name of the method invoked in this expression. + * + * @return the method name node + */ + public SimpleName getName() + { + if (this.methodName == null) + { + // lazy init must be thread-safe for readers + synchronized (this) + { + if (this.methodName == null) + { + preLazyInit(); + this.methodName = new SimpleName(this.ast); + postLazyInit(this.methodName, NAME_PROPERTY); + } + } + } + return this.methodName; + } + + /** + * Sets the name of the method invoked in this expression to the + * given name. + * + * @param name the new method name + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public void setName(SimpleName name) + { + if (name == null) + { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.methodName; + preReplaceChild(oldChild, name, NAME_PROPERTY); + this.methodName = name; + postReplaceChild(oldChild, name, NAME_PROPERTY); + } + + /** + * Returns the ordered list of argument expressions in this + * base call method send expression. + * + * @return the live list of argument expressions + * (element type: <code>Expression</code>) + */ + @SuppressWarnings("rawtypes") + public List getArguments() + { + return this.arguments; + } + + /** + * Returns the qualifier of this qualified creation expression, or + * <code>null</code> if there is none. + * + * @return the qualifier name node, or <code>null</code> if there is none + */ + public Name getQualifier() + { + return this.optionalQualification; + } + + + /** + * Sets the tsuper qualification + * + * @param qualification the new qualification + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public void setQualification(Name qualification) + { + if (qualification == null) + { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.optionalQualification; + preReplaceChild(oldChild, qualification, QUALIFIER_PROPERTY); + this.optionalQualification = qualification; + postReplaceChild(oldChild, qualification, QUALIFIER_PROPERTY); + } + + + final boolean subtreeMatch0(ASTMatcher matcher, Object other) + { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + void accept0(ASTVisitor visitor) + { + boolean visitChildren = visitor.visit(this); + if (visitChildren) + { + // visit children in normal left to right reading order + acceptChild(visitor, this.optionalQualification); + acceptChild(visitor, this.methodName); + acceptChildren(visitor, this.arguments); + } + visitor.endVisit(this); + } + + int memSize() + { + // treat Operator as free + return BASE_NODE_SIZE + 4 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() + { + return + memSize() + + (this.methodName == null ? 0 : this.methodName.treeSize()) + + (this.arguments == null ? 0 : this.arguments.listSize()); + } + + public IMethodBinding resolveMethodBinding() { + return this.ast.getBindingResolver().resolveMethod(this); + } + +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TagElement.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TagElement.java new file mode 100644 index 000000000..2261a2ad5 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TagElement.java @@ -0,0 +1,400 @@ +/******************************************************************************* + * Copyright (c) 2004, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * AST node for a tag within a doc comment. + * Tag elements nested within another tag element are called + * inline doc tags. + * <pre> + * TagElement: + * [ <b>@</b> Identifier ] { DocElement } + * DocElement: + * TextElement + * Name + * MethodRef + * MemberRef + * <b>{</b> TagElement <b>}</b> + * </pre> + * + * @see Javadoc + * @since 3.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public final class TagElement extends ASTNode implements IDocElement { + + /** + * The "tagName" structural property of this node type. + * + * @since 3.0 + */ + public static final SimplePropertyDescriptor TAG_NAME_PROPERTY = + new SimplePropertyDescriptor(TagElement.class, "tagName", String.class, OPTIONAL); //$NON-NLS-1$ + + /** + * The "fragments" structural property of this node type. + * @since 3.0 + */ + public static final ChildListPropertyDescriptor FRAGMENTS_PROPERTY = + new ChildListPropertyDescriptor(TagElement.class, "fragments", IDocElement.class, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + * @since 3.0 + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List propertyList = new ArrayList(3); + createPropertyList(TagElement.class, propertyList); + addProperty(TAG_NAME_PROPERTY, propertyList); + addProperty(FRAGMENTS_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * Standard doc tag name (value {@value}). + */ + public static final String TAG_AUTHOR = "@author"; //$NON-NLS-1$ + + /** + * Standard inline doc tag name (value {@value}). + * <p> + * Note that this tag first appeared in J2SE 5. + * </p> + * @since 3.1 + */ + public static final String TAG_CODE = "@code"; //$NON-NLS-1$ + + /** + * Standard doc tag name (value {@value}). + */ + public static final String TAG_DEPRECATED = "@deprecated"; //$NON-NLS-1$ + + /** + * Standard inline doc tag name (value {@value}). + */ + public static final String TAG_DOCROOT = "@docRoot"; //$NON-NLS-1$ + + /** + * Standard doc tag name (value {@value}). + */ + public static final String TAG_EXCEPTION = "@exception"; //$NON-NLS-1$ + + /** + * Standard inline doc tag name (value {@value}). + */ + public static final String TAG_INHERITDOC = "@inheritDoc"; //$NON-NLS-1$ + + /** + * Standard inline doc tag name (value {@value}). + */ + public static final String TAG_LINK = "@link"; //$NON-NLS-1$ + + /** + * Standard inline doc tag name (value {@value}). + */ + public static final String TAG_LINKPLAIN = "@linkplain"; //$NON-NLS-1$ + + /** + * Standard inline doc tag name (value {@value}). + * <p> + * Note that this tag first appeared in J2SE 5. + * </p> + * @since 3.1 + */ + public static final String TAG_LITERAL = "@literal"; //$NON-NLS-1$ + + /** + * Standard doc tag name (value {@value}). + */ + public static final String TAG_PARAM = "@param"; //$NON-NLS-1$ + + /** + * Standard doc tag name (value {@value}). + */ + public static final String TAG_RETURN = "@return"; //$NON-NLS-1$ + + /** + * Standard doc tag name (value {@value}). + */ + public static final String TAG_SEE = "@see"; //$NON-NLS-1$ + + /** + * Standard doc tag name (value {@value}). + */ + public static final String TAG_SERIAL = "@serial"; //$NON-NLS-1$ + + /** + * Standard doc tag name (value {@value}). + */ + public static final String TAG_SERIALDATA= "@serialData"; //$NON-NLS-1$ + + /** + * Standard doc tag name (value {@value}). + */ + public static final String TAG_SERIALFIELD= "@serialField"; //$NON-NLS-1$ + + /** + * Standard doc tag name (value {@value}). + */ + public static final String TAG_SINCE = "@since"; //$NON-NLS-1$ + + /** + * Standard doc tag name (value {@value}). + */ + public static final String TAG_THROWS = "@throws"; //$NON-NLS-1$ + + /** + * Standard inline doc tag name (value {@value}). + */ + public static final String TAG_VALUE= "@value"; //$NON-NLS-1$ + + /** + * Standard doc tag name (value {@value}). + */ + public static final String TAG_VERSION = "@version"; //$NON-NLS-1$ + + /** + * The tag name, or null if none; defaults to null. + */ + private String optionalTagName = null; + + /** + * The list of doc elements (element type: <code>IDocElement</code>). + * Defaults to an empty list. + */ + private ASTNode.NodeList fragments = + new ASTNode.NodeList(FRAGMENTS_PROPERTY); + + /** + * Creates a new AST node for a tag element owned by the given AST. + * The new node has no name and an empty list of fragments. + * <p> + * N.B. This constructor is package-private; all subclasses must be + * declared in the same package; clients are unable to declare + * additional subclasses. + * </p> + * + * @param ast the AST that is to own this node + */ + TagElement(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final Object internalGetSetObjectProperty(SimplePropertyDescriptor property, boolean get, Object value) { + if (property == TAG_NAME_PROPERTY) { + if (get) { + return getTagName(); + } else { + setTagName((String) value); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetObjectProperty(property, get, value); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalGetChildListProperty(ChildListPropertyDescriptor property) { + if (property == FRAGMENTS_PROPERTY) { + return fragments(); + } + // allow default implementation to flag the error + return super.internalGetChildListProperty(property); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return TAG_ELEMENT; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + TagElement result = new TagElement(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setTagName(getTagName()); + result.fragments().addAll(ASTNode.copySubtrees(target, fragments())); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + acceptChildren(visitor, this.fragments); + } + visitor.endVisit(this); + } + + /** + * Returns this node's tag name, or <code>null</code> if none. + * For top level doc tags such as parameter tags, the tag name + * includes the "@" character ("@param"). + * For inline doc tags such as link tags, the tag name + * includes the "@" character ("@link"). + * The tag name may also be <code>null</code>; this is used to + * represent the material at the start of a doc comment preceding + * the first explicit tag. + * + * @return the tag name, or <code>null</code> if none + */ + public String getTagName() { + return this.optionalTagName; + } + + /** + * Sets the tag name of this node to the given value. + * For top level doc tags such as parameter tags, the tag name + * includes the "@" character ("@param"). + * For inline doc tags such as link tags, the tag name + * includes the "@" character ("@link"). + * The tag name may also be <code>null</code>; this is used to + * represent the material at the start of a doc comment preceding + * the first explicit tag. + * + * @param tagName the tag name, or <code>null</code> if none + */ + public void setTagName(String tagName) { + preValueChange(TAG_NAME_PROPERTY); + this.optionalTagName = tagName; + postValueChange(TAG_NAME_PROPERTY); + } + + /** + * Returns the live list of fragments in this tag element. + * <p> + * The fragments cover everything following the tag name + * (or everything if there is no tag name), and generally omit + * embedded line breaks (and leading whitespace on new lines, + * including any leading "*"). {@link org.eclipse.jdt.core.dom.TagElement} + * nodes are used to represent tag elements (e.g., "@link") + * nested within this tag element. + * </p> + * <p> + * Here are some typical examples: + * <ul> + * <li>"@see Foo#bar()" - TagElement with tag name "@see"; + * fragments() contains a single MethodRef node</li> + * <li>"@param args the program arguments" - + * TagElement with tag name "@param"; + * 2 fragments: SimpleName ("args"), TextElement + * (" the program arguments")</li> + * <li>"@return See {@link #foo foo} instead." - + * TagElement with tag name "@return"; + * 3 fragments: TextElement ("See "), + * TagElement (for "@link #foo foo"), + * TextElement (" instead.")</li> + * </ul> + * The use of Name, MethodRef, and MemberRef nodes within + * tag elements allows these fragments to be queried for + * binding information. + * </p> + * <p> + * Adding and removing nodes from this list affects this node + * dynamically. The nodes in this list may be of various + * types, including {@link TextElement}, + * {@link org.eclipse.jdt.core.dom.TagElement}, {@link Name}, + * {@link MemberRef}, and {@link MethodRef}. + * Clients should assume that the list of types may grow in + * the future, and write their code to deal with unexpected + * nodes types. However, attempts to add a non-proscribed type + * of node will trigger an exception. + * + * @return the live list of doc elements in this tag element + * (element type: <code>ASTNode</code>) + */ + public List fragments() { + return this.fragments; + } + + /** + * Returns whether this tag element is nested within another + * tag element. Nested tag elements appears enclosed in + * "{" and "}"; certain doc tags, including "@link" and + * "@linkplain" are only meaningful as nested tags. + * Top-level (i.e., non-nested) doc tags begin on a new line; + * certain doc tags, including "@param" and + * "@see" are only meaningful as top-level tags. + * <p> + * This convenience methods checks to see whether the parent + * of this node is of type {@link org.eclipse.jdt.core.dom.TagElement}. + * </p> + * + * @return <code>true</code> if this node is a nested tag element, + * and false if this node is either parented by a doc comment node + * ({@link Javadoc}), or is unparented + */ + public boolean isNested() { + return (getParent() instanceof TagElement); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + int size = BASE_NODE_SIZE + 2 * 4 + stringSize(this.optionalTagName); + return size; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return memSize() + this.fragments.listSize(); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TextElement.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TextElement.java new file mode 100644 index 000000000..4bae86903 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TextElement.java @@ -0,0 +1,198 @@ +/******************************************************************************* + * Copyright (c) 2004, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jdt.internal.compiler.util.Util; + +/** + * AST node for a text element within a doc comment. + * <pre> + * TextElement: + * Sequence of characters not including a close comment delimiter <b>*</b><b>/</b> + * </pre> + * + * @see Javadoc + * @since 3.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public final class TextElement extends ASTNode implements IDocElement { + + /** + * The "text" structural property of this node type. + * + * @since 3.0 + */ + public static final SimplePropertyDescriptor TEXT_PROPERTY = + new SimplePropertyDescriptor(TextElement.class, "text", String.class, MANDATORY); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + * @since 3.0 + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List propertyList = new ArrayList(2); + createPropertyList(TextElement.class, propertyList); + addProperty(TEXT_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The text element; defaults to the empty string. + */ + private String text = Util.EMPTY_STRING; + + /** + * Creates a new AST node for a text element owned by the given AST. + * The new node has an empty text string. + * <p> + * N.B. This constructor is package-private; all subclasses must be + * declared in the same package; clients are unable to declare + * additional subclasses. + * </p> + * + * @param ast the AST that is to own this node + */ + TextElement(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final Object internalGetSetObjectProperty(SimplePropertyDescriptor property, boolean get, Object value) { + if (property == TEXT_PROPERTY) { + if (get) { + return getText(); + } else { + setText((String) value); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetObjectProperty(property, get, value); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return TEXT_ELEMENT; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + TextElement result = new TextElement(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setText(getText()); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + visitor.visit(this); + visitor.endVisit(this); + } + + /** + * Returns this node's text. + * + * @return the text of this node + */ + public String getText() { + return this.text; + } + + /** + * Sets the text of this node to the given value. + * <p> + * The text element typically includes leading and trailing + * whitespace that separates it from the immediately preceding + * or following elements. The text element must not include + * a block comment closing delimiter "*"+"/". + * </p> + * + * @param text the text of this node + * @exception IllegalArgumentException if the text is null + * or contains a block comment closing delimiter + */ + public void setText(String text) { + if (text == null) { + throw new IllegalArgumentException(); + } + if (text.indexOf("*/") > 0) { //$NON-NLS-1$ + throw new IllegalArgumentException(); + } + preValueChange(TEXT_PROPERTY); + this.text = text; + postValueChange(TEXT_PROPERTY); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + int size = BASE_NODE_SIZE + 1 * 4; + if (this.text != Util.EMPTY_STRING) { + // everything but our empty string costs + size += stringSize(this.text); + } + return size; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return memSize(); + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ThisExpression.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ThisExpression.java new file mode 100644 index 000000000..aa5d8ab38 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ThisExpression.java @@ -0,0 +1,188 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Simple or qualified "this" AST node type. + * + * <pre> + * ThisExpression: + * [ ClassName <b>.</b> ] <b>this</b> + * </pre> + * <p> + * See <code>FieldAccess</code> for guidelines on handling other expressions + * that resemble qualified names. + * </p> + * + * @see FieldAccess + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class ThisExpression extends Expression { + + /** + * The "qualifier" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor QUALIFIER_PROPERTY = + new ChildPropertyDescriptor(ThisExpression.class, "qualifier", Name.class, OPTIONAL, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List propertyList = new ArrayList(2); + createPropertyList(ThisExpression.class, propertyList); + addProperty(QUALIFIER_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The optional qualifier; <code>null</code> for none; defaults to none. + */ + private Name optionalQualifier = null; + + /** + * Creates a new AST node for a "this" expression owned by the + * given AST. By default, there is no qualifier. + * + * @param ast the AST that is to own this node + */ + ThisExpression(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == QUALIFIER_PROPERTY) { + if (get) { + return getQualifier(); + } else { + setQualifier((Name) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return THIS_EXPRESSION; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + ThisExpression result = new ThisExpression(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setQualifier((Name) ASTNode.copySubtree(target, getQualifier())); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + acceptChild(visitor, getQualifier()); + } + visitor.endVisit(this); + } + + /** + * Returns the qualifier of this "this" expression, or + * <code>null</code> if there is none. + * + * @return the qualifier name node, or <code>null</code> if there is none + */ + public Name getQualifier() { + return this.optionalQualifier; + } + + /** + * Sets or clears the qualifier of this "this" expression. + * + * @param name the qualifier name node, or <code>null</code> if + * there is none + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public void setQualifier(Name name) { + ASTNode oldChild = this.optionalQualifier; + preReplaceChild(oldChild, name, QUALIFIER_PROPERTY); + this.optionalQualifier = name; + postReplaceChild(oldChild, name, QUALIFIER_PROPERTY); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + // treat Operator as free + return BASE_NODE_SIZE + 1 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.optionalQualifier == null ? 0 : getQualifier().treeSize()); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ThrowStatement.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ThrowStatement.java new file mode 100644 index 000000000..9b3cf78d5 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ThrowStatement.java @@ -0,0 +1,201 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Throw statement AST node type. + * + * <pre> + * ThrowStatement: + * <b>throw</b> Expression <b>;</b> + * </pre> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class ThrowStatement extends Statement { + + /** + * The "expression" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor EXPRESSION_PROPERTY = + new ChildPropertyDescriptor(ThrowStatement.class, "expression", Expression.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List propertyList = new ArrayList(2); + createPropertyList(ThrowStatement.class, propertyList); + addProperty(EXPRESSION_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The expression; lazily initialized; defaults to a unspecified, but legal, + * expression. + */ + private Expression expression = null; + + /** + * Creates a new unparented throw statement node owned by the given + * AST. By default, the throw statement has an unspecified, but legal, + * expression. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + ThrowStatement(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == EXPRESSION_PROPERTY) { + if (get) { + return getExpression(); + } else { + setExpression((Expression) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return THROW_STATEMENT; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + ThrowStatement result = new ThrowStatement(target); + result.setSourceRange(getStartPosition(), getLength()); + result.copyLeadingComment(this); + result.setExpression((Expression) getExpression().clone(target)); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + acceptChild(visitor, getExpression()); + } + visitor.endVisit(this); + } + + /** + * Returns the expression of this throw statement. + * + * @return the expression node + */ + public Expression getExpression() { + if (this.expression == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.expression == null) { + preLazyInit(); + this.expression = new SimpleName(this.ast); + postLazyInit(this.expression, EXPRESSION_PROPERTY); + } + } + } + return this.expression; + } + + /** + * Sets the expression of this throw statement. + * + * @param expression the new expression node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setExpression(Expression expression) { + if (expression == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.expression; + preReplaceChild(oldChild, expression, EXPRESSION_PROPERTY); + this.expression = expression; + postReplaceChild(oldChild, expression, EXPRESSION_PROPERTY); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return super.memSize() + 1 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.expression == null ? 0 : getExpression().treeSize()); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TryStatement.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TryStatement.java new file mode 100644 index 000000000..1afbee8b1 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TryStatement.java @@ -0,0 +1,299 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Try statement AST node type. + * + * <pre> + * TryStatement: + * <b>try</b> Block + * { CatchClause } + * [ <b>finally</b> Block ] + * </pre> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class TryStatement extends Statement { + + /** + * The "body" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor BODY_PROPERTY = + new ChildPropertyDescriptor(TryStatement.class, "body", Block.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "catchClauses" structural property of this node type. + * @since 3.0 + */ + public static final ChildListPropertyDescriptor CATCH_CLAUSES_PROPERTY = + new ChildListPropertyDescriptor(TryStatement.class, "catchClauses", CatchClause.class, CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "finally" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor FINALLY_PROPERTY = + new ChildPropertyDescriptor(TryStatement.class, "finally", Block.class, OPTIONAL, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List propertyList = new ArrayList(4); + createPropertyList(TryStatement.class, propertyList); + addProperty(BODY_PROPERTY, propertyList); + addProperty(CATCH_CLAUSES_PROPERTY, propertyList); + addProperty(FINALLY_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The body; lazily initialized; defaults to an empty block. + */ + private Block body = null; + + /** + * The catch clauses (element type: <code>CatchClause</code>). + * Defaults to an empty list. + */ + private ASTNode.NodeList catchClauses = + new ASTNode.NodeList(CATCH_CLAUSES_PROPERTY); + + /** + * The finally block, or <code>null</code> if none. + * Defaults to none. + */ + private Block optionalFinallyBody = null; + + + /** + * Creates a new AST node for a try statement owned by the given + * AST. By default, the try statement has an empty block, no catch + * clauses, and no finally block. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + TryStatement(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == BODY_PROPERTY) { + if (get) { + return getBody(); + } else { + setBody((Block) child); + return null; + } + } + if (property == FINALLY_PROPERTY) { + if (get) { + return getFinally(); + } else { + setFinally((Block) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalGetChildListProperty(ChildListPropertyDescriptor property) { + if (property == CATCH_CLAUSES_PROPERTY) { + return catchClauses(); + } + // allow default implementation to flag the error + return super.internalGetChildListProperty(property); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return TRY_STATEMENT; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + TryStatement result = new TryStatement(target); + result.setSourceRange(getStartPosition(), getLength()); + result.copyLeadingComment(this); + result.setBody((Block) getBody().clone(target)); + result.catchClauses().addAll( + ASTNode.copySubtrees(target, catchClauses())); + result.setFinally( + (Block) ASTNode.copySubtree(target, getFinally())); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + acceptChild(visitor, getBody()); + acceptChildren(visitor, this.catchClauses); + acceptChild(visitor, getFinally()); + } + visitor.endVisit(this); + } + + /** + * Returns the body of this try statement. + * + * @return the try body + */ + public Block getBody() { + if (this.body == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.body == null) { + preLazyInit(); + this.body = new Block(this.ast); + postLazyInit(this.body, BODY_PROPERTY); + } + } + } + return this.body; + } + + /** + * Sets the body of this try statement. + * + * @param body the block node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setBody(Block body) { + if (body == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.body; + preReplaceChild(oldChild, body, BODY_PROPERTY); + this.body = body; + postReplaceChild(oldChild, body, BODY_PROPERTY); + } + + /** + * Returns the live ordered list of catch clauses for this try statement. + * + * @return the live list of catch clauses + * (element type: <code>CatchClause</code>) + */ + public List catchClauses() { + return this.catchClauses; + } + + /** + * Returns the finally block of this try statement, or <code>null</code> if + * this try statement has <b>no</b> finally block. + * + * @return the finally block, or <code>null</code> if this try statement + * has none + */ + public Block getFinally() { + return this.optionalFinallyBody; + } + + /** + * Sets or clears the finally block of this try statement. + * + * @param block the finally block node, or <code>null</code> if + * there is none + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setFinally(Block block) { + ASTNode oldChild = this.optionalFinallyBody; + preReplaceChild(oldChild, block, FINALLY_PROPERTY); + this.optionalFinallyBody = block; + postReplaceChild(oldChild, block, FINALLY_PROPERTY); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return super.memSize() + 3 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.body == null ? 0 : getBody().treeSize()) + + this.catchClauses.listSize() + + (this.optionalFinallyBody == null ? 0 : getFinally().treeSize()); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Type.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Type.java new file mode 100644 index 000000000..6504333d8 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Type.java @@ -0,0 +1,171 @@ +/******************************************************************************* + * Copyright (c) 2000, 2009 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +/** + * Abstract base class of all type AST node types. A type node represents a + * reference to a primitive type (including void), to an array type, or to a + * simple named type (or type variable), to a qualified type, to a + * parameterized type, or to a wildcard type. Note that not all of these + * are meaningful in all contexts; for example, a wildcard type is only + * meaningful in the type argument position of a parameterized type. + * <p> + * <pre> + * Type: + * PrimitiveType + * ArrayType + * SimpleType + * QualifiedType + * ParameterizedType + * WildcardType + * PrimitiveType: + * <b>byte</b> + * <b>short</b> + * <b>char</b> + * <b>int</b> + * <b>long</b> + * <b>float</b> + * <b>double</b> + * <b>boolean</b> + * <b>void</b> + * ArrayType: + * Type <b>[</b> <b>]</b> + * SimpleType: + * TypeName + * ParameterizedType: + * Type <b><</b> Type { <b>,</b> Type } <b>></b> + * QualifiedType: + * Type <b>.</b> SimpleName + * WildcardType: + * <b>?</b> [ ( <b>extends</b> | <b>super</b>) Type ] + * </pre> + * </p> + * + * @since 2.0 + */ +public abstract class Type extends ASTNode { + + /** + * Creates a new AST node for a type owned by the given AST. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + Type(AST ast) { + super(ast); + } + + /** + * Returns whether this type is a primitive type + * (<code>PrimitiveType</code>). + * + * @return <code>true</code> if this is a primitive type, and + * <code>false</code> otherwise + */ + public final boolean isPrimitiveType() { + return (this instanceof PrimitiveType); + } + + /** + * Returns whether this type is a simple type + * (<code>SimpleType</code>). + * + * @return <code>true</code> if this is a simple type, and + * <code>false</code> otherwise + */ + public final boolean isSimpleType() { + return (this instanceof SimpleType); + } + + /** + * Returns whether this type is an array type + * (<code>ArrayType</code>). + * + * @return <code>true</code> if this is an array type, and + * <code>false</code> otherwise + */ + public final boolean isArrayType() { + return (this instanceof ArrayType); + } + + /** + * Returns whether this type is a parameterized type + * (<code>ParameterizedType</code>). + * + * @return <code>true</code> if this is a parameterized type, and + * <code>false</code> otherwise + * @since 3.1 + */ + public final boolean isParameterizedType() { + return (this instanceof ParameterizedType); + } + + /** + * Returns whether this type is a qualified type + * (<code>QualifiedType</code>). + * <p> + * Note that a type like "A.B" can be represented either of two ways: + * <ol> + * <li> + * <code>QualifiedType(SimpleType(SimpleName("A")),SimpleName("B"))</code> + * </li> + * <li> + * <code>SimpleType(QualifiedName(SimpleName("A"),SimpleName("B")))</code> + * </li> + * </ol> + * The first form is preferred when "A" is known to be a type. However, a + * parser cannot always determine this. Clients should be prepared to handle + * either rather than make assumptions. (Note also that the first form + * became possible as of JLS3; only the second form existed in the + * JLS2 API.) + * </p> + * + * @return <code>true</code> if this is a qualified type, and + * <code>false</code> otherwise + * @since 3.1 + */ + public final boolean isQualifiedType() { + return (this instanceof QualifiedType); + } + + /** + * Returns whether this type is a wildcard type + * (<code>WildcardType</code>). + * <p> + * Note that a wildcard type is only meaningful as a + * type argument of a <code>ParameterizedType</code> node. + * </p> + * + * @return <code>true</code> if this is a wildcard type, and + * <code>false</code> otherwise + * @since 3.1 + */ + public final boolean isWildcardType() { + return (this instanceof WildcardType); + } + + /** + * Resolves and returns the binding for this type. + * <p> + * Note that bindings are generally unavailable unless requested when the + * AST is being built. + * </p> + * + * @return the type binding, or <code>null</code> if the binding cannot be + * resolved + */ + public final ITypeBinding resolveBinding() { + return this.ast.getBindingResolver().resolveType(this); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeAnchor.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeAnchor.java new file mode 100644 index 000000000..c80e18746 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeAnchor.java @@ -0,0 +1,199 @@ +/********************************************************************** + * This file is part of "Object Teams Development Tooling"-Software + * + * Copyright 2006 Fraunhofer Gesellschaft, Munich, Germany, + * for its Fraunhofer Institute for Computer Architecture and Software + * Technology (FIRST), Berlin, Germany and Technical University Berlin, + * Germany. + * + * 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 + * $Id: LiftingType.java 14417 2006-09-23 11:18:42Z stephan $ + * + * Please visit http://www.eclipse.org/objectteams for updates and contact. + * + * Contributors: + * Fraunhofer FIRST - Initial API and implementation + * Technical University Berlin - Initial API and implementation + **********************************************************************/ +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; +/** + * NEW for OTDT + * + * This class represents the anchor "@anchor" of a dependent type T<@anchor>. + * For the compiler this is a value reference but syntactically we treat it + * as a type reference so the whole type can mimic as a regular generic type. + * + * @author stephan + * @version $Id: LiftingType.java 14417 2006-09-23 11:18:42Z stephan $ + */ +public class TypeAnchor extends Type { + + /** + * The "path" structural property of this node type. + */ + public static final ChildPropertyDescriptor PATH_PROPERTY = + new ChildPropertyDescriptor(TypeAnchor.class, "path", Name.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + @SuppressWarnings("rawtypes") + private static final List PROPERTY_DESCRIPTORS; + + static + { + List<StructuralPropertyDescriptor> propertyList = new ArrayList<StructuralPropertyDescriptor>(2); + createPropertyList(TypeAnchor.class, propertyList); + addProperty(PATH_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + */ + @SuppressWarnings("rawtypes") + public static List propertyDescriptors(int apiLevel) + { + return PROPERTY_DESCRIPTORS; + } + + /** + * The path node; lazily initialized; defaults to a unspecified, but legal, path. + */ + private Name path = null; + + + /** + * Creates a new unparented node for a type anchor owned by the given AST. + * By default, an unspecified, but legal, expression. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + TypeAnchor(AST ast) + { + super(ast); + } + + @SuppressWarnings("rawtypes") + @Override + final List internalStructuralPropertiesForType(int apiLevel) + { + return propertyDescriptors(apiLevel); + } + + @Override + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) + { + if (property == PATH_PROPERTY) + { + if (get) + { + return getPath(); + } + else + { + setPath((Name) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /** + * Returns the path of this type anchor. + * + * @return the path node + */ + public Name getPath() { + if (this.path == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.path == null) { + preLazyInit(); + this.path = new SimpleName(this.ast); + postLazyInit(this.path, PATH_PROPERTY); + } + } + } + return this.path; + } + + /** + * Sets the path of this type anchor. + * + * @param path the new path node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setPath(Name path) { + if (path == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.path; + preReplaceChild(oldChild, path, PATH_PROPERTY); + this.path = path; + postReplaceChild(oldChild, path, PATH_PROPERTY); + } + + @Override + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + acceptChild(visitor, getPath()); + } + visitor.endVisit(this); + } + + @Override + ASTNode clone0(AST target) { + TypeAnchor result = new TypeAnchor(target); + result.setSourceRange(this.getStartPosition(), this.getLength()); + result.setPath((Name) getPath().clone(target)); + return result; + } + + @Override + int getNodeType0() { + return TYPE_ANCHOR; + } + + @Override + int memSize() { + return BASE_NODE_SIZE + 1 * 4; + } + + @Override + boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + @Override + int treeSize() { + return memSize() + + (this.path == null ? 0 : getPath().treeSize()); + } + +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeBinding.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeBinding.java new file mode 100644 index 000000000..c75ae1bc1 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeBinding.java @@ -0,0 +1,1463 @@ +/******************************************************************************* + * Copyright (c) 2000, 2009 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 + * $Id: TypeBinding.java 23405 2010-02-03 17:02:18Z stephan $ + * + * Contributors: + * IBM Corporation - initial API and implementation + * Fraunhofer FIRST - extended API and implementation + * Technical University Berlin - extended API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.ast.Expression; +import org.eclipse.jdt.internal.compiler.ast.Wildcard; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding; +import org.eclipse.jdt.internal.compiler.lookup.BaseTypeBinding; +import org.eclipse.jdt.internal.compiler.lookup.Binding; +import org.eclipse.jdt.internal.compiler.lookup.CaptureBinding; +import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; +import org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding; +import org.eclipse.jdt.internal.compiler.lookup.MemberTypeBinding; +import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; +import org.eclipse.jdt.internal.compiler.lookup.PackageBinding; +import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding; +import org.eclipse.jdt.internal.compiler.lookup.RawTypeBinding; +import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; +import org.eclipse.jdt.internal.compiler.lookup.Scope; +import org.eclipse.jdt.internal.compiler.lookup.TagBits; +import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; +import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding; +import org.eclipse.jdt.internal.compiler.lookup.WildcardBinding; +import org.eclipse.jdt.internal.compiler.problem.AbortCompilation; +import org.eclipse.jdt.internal.compiler.util.SuffixConstants; +import org.eclipse.jdt.internal.core.JavaElement; +import org.eclipse.jdt.internal.core.PackageFragment; +import org.eclipse.objectteams.otdt.core.compiler.IOTConstants; +import org.eclipse.objectteams.otdt.internal.core.compiler.control.Dependencies; +import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.CallinCalloutBinding; +import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.DependentTypeBinding; +import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.ITeamAnchor; +import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.RoleTypeBinding; +import org.eclipse.objectteams.otdt.internal.core.compiler.model.RoleModel; + +/** + * MIGRATION_STATE: 3.4 + * + * <h4>OTDT changes:</h4> + * <dl> + * <dt>What:<dd> implement methods from ITypeBinding + * + * <dt>What:<dd> Check for role files. + * </dl> + * <hr> + * Internal implementation of type bindings. + */ +class TypeBinding implements ITypeBinding { + protected static final IMethodBinding[] NO_METHOD_BINDINGS = new IMethodBinding[0]; + + private static final String NO_NAME = ""; //$NON-NLS-1$ + protected static final ITypeBinding[] NO_TYPE_BINDINGS = new ITypeBinding[0]; + protected static final IVariableBinding[] NO_VARIABLE_BINDINGS = new IVariableBinding[0]; + + private static final int VALID_MODIFIERS = Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE | + Modifier.ABSTRACT | Modifier.STATIC | Modifier.FINAL | Modifier.STRICTFP; + + org.eclipse.jdt.internal.compiler.lookup.TypeBinding binding; + private String key; + private BindingResolver resolver; + private IVariableBinding[] fields; + private IAnnotationBinding[] annotations; + private IMethodBinding[] methods; + private ITypeBinding[] members; + private ITypeBinding[] interfaces; + private ITypeBinding[] typeArguments; + private ITypeBinding[] bounds; + private ITypeBinding[] typeParameters; + + public TypeBinding(BindingResolver resolver, org.eclipse.jdt.internal.compiler.lookup.TypeBinding binding) { + this.binding = binding; + this.resolver = resolver; + } + + public ITypeBinding createArrayType(int dimension) { + int realDimensions = dimension; + realDimensions += getDimensions(); + if (realDimensions < 1 || realDimensions > 255) { + throw new IllegalArgumentException(); + } + return this.resolver.resolveArrayType(this, dimension); + } + + public IAnnotationBinding[] getAnnotations() { + if (this.annotations != null) { + return this.annotations; + } + if (this.binding.isAnnotationType() || this.binding.isClass() || this.binding.isEnum() || this.binding.isInterface()) { + org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding refType = + (org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding) this.binding; +//{ObjectTeams: calling getAnnotations() requires Dependencies control: +/* orig: + org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding[] internalAnnotations = refType.getAnnotations(); + :giro */ + org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding[] internalAnnotations = null; + Dependencies.setup(this, null, this.resolver.lookupEnvironment(), true, true); // TODO(SH): parser, flags? + try { + internalAnnotations = refType.getAnnotations(); + } finally { + Dependencies.release(this); + } +// SH} + int length = internalAnnotations == null ? 0 : internalAnnotations.length; + if (length != 0) { + IAnnotationBinding[] tempAnnotations = new IAnnotationBinding[length]; + int convertedAnnotationCount = 0; + for (int i = 0; i < length; i++) { + org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding internalAnnotation = internalAnnotations[i]; + IAnnotationBinding annotationInstance = this.resolver.getAnnotationInstance(internalAnnotation); + if (annotationInstance == null) { + continue; + } + tempAnnotations[convertedAnnotationCount++] = annotationInstance; + } + if (convertedAnnotationCount != length) { + if (convertedAnnotationCount == 0) { + return this.annotations = AnnotationBinding.NoAnnotations; + } + System.arraycopy(tempAnnotations, 0, (tempAnnotations = new IAnnotationBinding[convertedAnnotationCount]), 0, convertedAnnotationCount); + } + return this.annotations = tempAnnotations; + } + } + return this.annotations = AnnotationBinding.NoAnnotations; + } + + /* + * @see ITypeBinding#getBinaryName() + * @since 3.0 + */ + public String getBinaryName() { + if (this.binding.isCapture()) { + return null; // no binary name for capture binding + } else if (this.binding.isTypeVariable()) { + TypeVariableBinding typeVariableBinding = (TypeVariableBinding) this.binding; + org.eclipse.jdt.internal.compiler.lookup.Binding declaring = typeVariableBinding.declaringElement; + StringBuffer binaryName = new StringBuffer(); + switch(declaring.kind()) { + case org.eclipse.jdt.internal.compiler.lookup.Binding.METHOD : + MethodBinding methodBinding = (MethodBinding) declaring; + char[] constantPoolName = methodBinding.declaringClass.constantPoolName(); + if (constantPoolName == null) return null; + binaryName + .append(CharOperation.replaceOnCopy(constantPoolName, '/', '.')) + .append('$') + .append(methodBinding.signature()) + .append('$') + .append(typeVariableBinding.sourceName); + break; + default : + org.eclipse.jdt.internal.compiler.lookup.TypeBinding typeBinding = (org.eclipse.jdt.internal.compiler.lookup.TypeBinding) declaring; + constantPoolName = typeBinding.constantPoolName(); + if (constantPoolName == null) return null; + binaryName + .append(CharOperation.replaceOnCopy(constantPoolName, '/', '.')) + .append('$') + .append(typeVariableBinding.sourceName); + } + return String.valueOf(binaryName); + } + char[] constantPoolName = this.binding.constantPoolName(); + if (constantPoolName == null) return null; + char[] dotSeparated = CharOperation.replaceOnCopy(constantPoolName, '/', '.'); + return new String(dotSeparated); + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#getBound() + */ + public ITypeBinding getBound() { + switch (this.binding.kind()) { + case Binding.WILDCARD_TYPE : + case Binding.INTERSECTION_TYPE : + WildcardBinding wildcardBinding = (WildcardBinding) this.binding; + if (wildcardBinding.bound != null) { + return this.resolver.getTypeBinding(wildcardBinding.bound); + } + break; + } + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#getGenericTypeOfWildcardType() + */ + public ITypeBinding getGenericTypeOfWildcardType() { + switch (this.binding.kind()) { + case Binding.WILDCARD_TYPE : + case Binding.INTERSECTION_TYPE : + WildcardBinding wildcardBinding = (WildcardBinding) this.binding; + if (wildcardBinding.genericType != null) { + return this.resolver.getTypeBinding(wildcardBinding.genericType); + } + break; + } + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#getRank() + */ + public int getRank() { + switch (this.binding.kind()) { + case Binding.WILDCARD_TYPE : + case Binding.INTERSECTION_TYPE : + WildcardBinding wildcardBinding = (WildcardBinding) this.binding; + return wildcardBinding.rank; + default: + return -1; + } + } + + /* + * @see ITypeBinding#getComponentType() + */ + public ITypeBinding getComponentType() { + if (!isArray()) { + return null; + } + ArrayBinding arrayBinding = (ArrayBinding) this.binding; + return this.resolver.getTypeBinding(arrayBinding.elementsType()); + } + + /* + * @see ITypeBinding#getDeclaredFields() + */ + public synchronized IVariableBinding[] getDeclaredFields() { + if (this.fields != null) { + return this.fields; + } +//{ObjectTeams: may need Dependencies: + boolean usesDependencies = false; +// SH} + try { + if (isClass() || isInterface() || isEnum()) { +//{ObjectTeams: calling methods() requires Dependencies control: + Dependencies.setup(this, null, this.resolver.lookupEnvironment(), true, true); // TODO(SH): parser, flags? + usesDependencies = true; +// SH} + ReferenceBinding referenceBinding = (ReferenceBinding) this.binding; + FieldBinding[] fieldBindings = referenceBinding.availableFields(); // resilience + int length = fieldBindings.length; + if (length != 0) { + int convertedFieldCount = 0; + IVariableBinding[] newFields = new IVariableBinding[length]; + for (int i = 0; i < length; i++) { + FieldBinding fieldBinding = fieldBindings[i]; + IVariableBinding variableBinding = this.resolver.getVariableBinding(fieldBinding); + if (variableBinding != null) { + newFields[convertedFieldCount++] = variableBinding; + } + } + + if (convertedFieldCount != length) { + if (convertedFieldCount == 0) { + return this.fields = NO_VARIABLE_BINDINGS; + } + System.arraycopy(newFields, 0, (newFields = new IVariableBinding[convertedFieldCount]), 0, convertedFieldCount); + } + return this.fields = newFields; + } + } + } catch (RuntimeException e) { + /* in case a method cannot be resolvable due to missing jars on the classpath + * see https://bugs.eclipse.org/bugs/show_bug.cgi?id=57871 + * https://bugs.eclipse.org/bugs/show_bug.cgi?id=63550 + * https://bugs.eclipse.org/bugs/show_bug.cgi?id=64299 + */ + org.eclipse.jdt.internal.core.util.Util.log(e, "Could not retrieve declared fields"); //$NON-NLS-1$ + } +//{ObjectTeams: cleanup: + finally { + if (usesDependencies) + Dependencies.release(this); + } +// SH} + return this.fields = NO_VARIABLE_BINDINGS; + } + + /* + * @see ITypeBinding#getDeclaredMethods() + */ + public synchronized IMethodBinding[] getDeclaredMethods() { + if (this.methods != null) { + return this.methods; + } +//{ObjectTeams: may need Dependencies: + boolean usesDependencies = false; +// SH} + try { + if (isClass() || isInterface() || isEnum()) { +//{ObjectTeams: calling methods() requires Dependencies control: + Dependencies.setup(this, null, this.resolver.lookupEnvironment(), true, true); // TODO(SH): parser, flags? + usesDependencies = true; +// SH} + ReferenceBinding referenceBinding = (ReferenceBinding) this.binding; + org.eclipse.jdt.internal.compiler.lookup.MethodBinding[] internalMethods = referenceBinding.availableMethods(); // be resilient + int length = internalMethods.length; + if (length != 0) { + int convertedMethodCount = 0; + IMethodBinding[] newMethods = new IMethodBinding[length]; + for (int i = 0; i < length; i++) { + org.eclipse.jdt.internal.compiler.lookup.MethodBinding methodBinding = internalMethods[i]; + if (methodBinding.isDefaultAbstract() || methodBinding.isSynthetic() || (methodBinding.isConstructor() && isInterface())) { + continue; + } + if ( methodBinding.copyInheritanceSrc != null + || CharOperation.prefixEquals(IOTConstants.OT_DOLLAR_NAME, methodBinding.selector())) + continue; + IMethodBinding methodBinding2 = this.resolver.getMethodBinding(methodBinding); + if (methodBinding2 != null) { + newMethods[convertedMethodCount++] = methodBinding2; + } + } + if (convertedMethodCount != length) { + if (convertedMethodCount == 0) { + return this.methods = NO_METHOD_BINDINGS; + } + System.arraycopy(newMethods, 0, (newMethods = new IMethodBinding[convertedMethodCount]), 0, convertedMethodCount); + } + return this.methods = newMethods; + } + } + } catch (RuntimeException e) { + /* in case a method cannot be resolvable due to missing jars on the classpath + * see https://bugs.eclipse.org/bugs/show_bug.cgi?id=57871 + * https://bugs.eclipse.org/bugs/show_bug.cgi?id=63550 + * https://bugs.eclipse.org/bugs/show_bug.cgi?id=64299 + */ + org.eclipse.jdt.internal.core.util.Util.log(e, "Could not retrieve declared methods"); //$NON-NLS-1$ + } +//{ObjectTeams: cleanup: + finally { + if (usesDependencies) + Dependencies.release(this); + } +// SH} + return this.methods = NO_METHOD_BINDINGS; + } + + /* + * @see ITypeBinding#getDeclaredModifiers() + */ + public int getDeclaredModifiers() { + return getModifiers(); + } + + /* + * @see ITypeBinding#getDeclaredTypes() + */ + public synchronized ITypeBinding[] getDeclaredTypes() { + if (this.members != null) { + return this.members; + } + try { + if (isClass() || isInterface() || isEnum()) { + ReferenceBinding referenceBinding = (ReferenceBinding) this.binding; + ReferenceBinding[] internalMembers = referenceBinding.memberTypes(); + int length = internalMembers.length; + if (length != 0) { + ITypeBinding[] newMembers = new ITypeBinding[length]; + for (int i = 0; i < length; i++) { + ITypeBinding typeBinding = this.resolver.getTypeBinding(internalMembers[i]); + if (typeBinding == null) { + return this.members = NO_TYPE_BINDINGS; + } + newMembers[i] = typeBinding; + } + return this.members = newMembers; + } + } + } catch (RuntimeException e) { + /* in case a method cannot be resolvable due to missing jars on the classpath + * see https://bugs.eclipse.org/bugs/show_bug.cgi?id=57871 + * https://bugs.eclipse.org/bugs/show_bug.cgi?id=63550 + * https://bugs.eclipse.org/bugs/show_bug.cgi?id=64299 + */ + org.eclipse.jdt.internal.core.util.Util.log(e, "Could not retrieve declared methods"); //$NON-NLS-1$ + } + return this.members = NO_TYPE_BINDINGS; + } + + /* + * @see ITypeBinding#getDeclaringMethod() + */ + public synchronized IMethodBinding getDeclaringMethod() { + if (this.binding instanceof LocalTypeBinding) { + LocalTypeBinding localTypeBinding = (LocalTypeBinding) this.binding; + MethodBinding methodBinding = localTypeBinding.enclosingMethod; + if (methodBinding != null) { + try { + return this.resolver.getMethodBinding(localTypeBinding.enclosingMethod); + } catch (RuntimeException e) { + /* in case a method cannot be resolvable due to missing jars on the classpath + * see https://bugs.eclipse.org/bugs/show_bug.cgi?id=57871 + * https://bugs.eclipse.org/bugs/show_bug.cgi?id=63550 + * https://bugs.eclipse.org/bugs/show_bug.cgi?id=64299 + */ + org.eclipse.jdt.internal.core.util.Util.log(e, "Could not retrieve declaring method"); //$NON-NLS-1$ + } + } + } else if (this.binding.isTypeVariable()) { + TypeVariableBinding typeVariableBinding = (TypeVariableBinding) this.binding; + Binding declaringElement = typeVariableBinding.declaringElement; + if (declaringElement instanceof MethodBinding) { + try { + return this.resolver.getMethodBinding((MethodBinding)declaringElement); + } catch (RuntimeException e) { + /* in case a method cannot be resolvable due to missing jars on the classpath + * see https://bugs.eclipse.org/bugs/show_bug.cgi?id=57871 + * https://bugs.eclipse.org/bugs/show_bug.cgi?id=63550 + * https://bugs.eclipse.org/bugs/show_bug.cgi?id=64299 + */ + org.eclipse.jdt.internal.core.util.Util.log(e, "Could not retrieve declaring method"); //$NON-NLS-1$ + } + } + } + return null; + } + + /* + * @see ITypeBinding#getDeclaringClass() + */ + public synchronized ITypeBinding getDeclaringClass() { + if (isClass() || isInterface() || isEnum()) { + ReferenceBinding referenceBinding = (ReferenceBinding) this.binding; + if (referenceBinding.isNestedType()) { + try { + return this.resolver.getTypeBinding(referenceBinding.enclosingType()); + } catch (RuntimeException e) { + /* in case a method cannot be resolvable due to missing jars on the classpath + * see https://bugs.eclipse.org/bugs/show_bug.cgi?id=57871 + * https://bugs.eclipse.org/bugs/show_bug.cgi?id=63550 + * https://bugs.eclipse.org/bugs/show_bug.cgi?id=64299 + */ + org.eclipse.jdt.internal.core.util.Util.log(e, "Could not retrieve declaring class"); //$NON-NLS-1$ + } + } + } else if (this.binding.isTypeVariable()) { + TypeVariableBinding typeVariableBinding = (TypeVariableBinding) this.binding; + Binding declaringElement = typeVariableBinding.isCapture() ? ((CaptureBinding) typeVariableBinding).sourceType : typeVariableBinding.declaringElement; + if (declaringElement instanceof ReferenceBinding) { + try { + return this.resolver.getTypeBinding((ReferenceBinding)declaringElement); + } catch (RuntimeException e) { + /* in case a method cannot be resolvable due to missing jars on the classpath + * see https://bugs.eclipse.org/bugs/show_bug.cgi?id=57871 + * https://bugs.eclipse.org/bugs/show_bug.cgi?id=63550 + * https://bugs.eclipse.org/bugs/show_bug.cgi?id=64299 + */ + org.eclipse.jdt.internal.core.util.Util.log(e, "Could not retrieve declaring class"); //$NON-NLS-1$ + } + } + } + return null; + } + + /* + * @see ITypeBinding#getDimensions() + */ + public int getDimensions() { + if (!isArray()) { + return 0; + } + ArrayBinding arrayBinding = (ArrayBinding) this.binding; + return arrayBinding.dimensions; + } + + /* + * @see ITypeBinding#getElementType() + */ + public ITypeBinding getElementType() { + if (!isArray()) { + return null; + } + ArrayBinding arrayBinding = (ArrayBinding) this.binding; + return this.resolver.getTypeBinding(arrayBinding.leafComponentType); + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#getTypeDeclaration() + */ + public ITypeBinding getTypeDeclaration() { + if (this.binding instanceof ParameterizedTypeBinding) + return this.resolver.getTypeBinding(((ParameterizedTypeBinding)this.binding).genericType()); + return this; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#getErasure() + */ + public ITypeBinding getErasure() { + return this.resolver.getTypeBinding(this.binding.erasure()); + } + + public synchronized ITypeBinding[] getInterfaces() { + if (this.interfaces != null) { + return this.interfaces; + } + if (this.binding == null) + return this.interfaces = NO_TYPE_BINDINGS; + switch (this.binding.kind()) { + case Binding.ARRAY_TYPE : + case Binding.BASE_TYPE : + return this.interfaces = NO_TYPE_BINDINGS; + } + ReferenceBinding referenceBinding = (ReferenceBinding) this.binding; + ReferenceBinding[] internalInterfaces = null; + try { + internalInterfaces = referenceBinding.superInterfaces(); + } catch (RuntimeException e) { + /* in case a method cannot be resolvable due to missing jars on the classpath + * see https://bugs.eclipse.org/bugs/show_bug.cgi?id=57871 + * https://bugs.eclipse.org/bugs/show_bug.cgi?id=63550 + * https://bugs.eclipse.org/bugs/show_bug.cgi?id=64299 + */ + org.eclipse.jdt.internal.core.util.Util.log(e, "Could not retrieve interfaces"); //$NON-NLS-1$ + } + int length = internalInterfaces == null ? 0 : internalInterfaces.length; + if (length != 0) { + ITypeBinding[] newInterfaces = new ITypeBinding[length]; + int interfacesCounter = 0; + for (int i = 0; i < length; i++) { + ITypeBinding typeBinding = this.resolver.getTypeBinding(internalInterfaces[i]); + if (typeBinding == null) { + continue; + } + newInterfaces[interfacesCounter++] = typeBinding; + } + if (length != interfacesCounter) { + System.arraycopy(newInterfaces, 0, (newInterfaces = new ITypeBinding[interfacesCounter]), 0, interfacesCounter); + } + return this.interfaces = newInterfaces; + } + return this.interfaces = NO_TYPE_BINDINGS; + } + + public IJavaElement getJavaElement() { + JavaElement element = getUnresolvedJavaElement(); + if (element != null) + return element.resolved(this.binding); + if (isRecovered()) { + IPackageBinding packageBinding = getPackage(); + if (packageBinding != null) { + final IJavaElement javaElement = packageBinding.getJavaElement(); + if (javaElement != null && javaElement.getElementType() == IJavaElement.PACKAGE_FRAGMENT) { + // best effort: we don't know if the recovered binding is a binary or source binding, so go with a compilation unit + return ((PackageFragment) javaElement).getCompilationUnit(new String(this.binding.sourceName()) + SuffixConstants.SUFFIX_STRING_java); + } + } + return null; + } + return null; + } + + private JavaElement getUnresolvedJavaElement() { + return getUnresolvedJavaElement(this.binding); + } + private JavaElement getUnresolvedJavaElement(org.eclipse.jdt.internal.compiler.lookup.TypeBinding typeBinding ) { + if (this.resolver instanceof DefaultBindingResolver) { + DefaultBindingResolver defaultBindingResolver = (DefaultBindingResolver) this.resolver; + return org.eclipse.jdt.internal.core.util.Util.getUnresolvedJavaElement( + typeBinding, + defaultBindingResolver.workingCopyOwner, + defaultBindingResolver.getBindingsToNodesMap()); + } else { + return org.eclipse.jdt.internal.core.util.Util.getUnresolvedJavaElement(typeBinding, null, null); + } + } + + /* + * @see IBinding#getKey() + */ + public String getKey() { + if (this.key == null) { + this.key = new String(this.binding.computeUniqueKey()); + } + return this.key; + } + + /* + * @see IBinding#getKind() + */ + public int getKind() { + return IBinding.TYPE; + } + + /* + * @see IBinding#getModifiers() + */ + public int getModifiers() { + if (isClass()) { + ReferenceBinding referenceBinding = (ReferenceBinding) this.binding; + final int accessFlags = referenceBinding.getAccessFlags() & VALID_MODIFIERS; + if (referenceBinding.isAnonymousType()) { + return accessFlags & ~Modifier.FINAL; + } + return accessFlags; + } else if (isAnnotation()) { + ReferenceBinding referenceBinding = (ReferenceBinding) this.binding; + final int accessFlags = referenceBinding.getAccessFlags() & VALID_MODIFIERS; + // clear the AccAbstract, AccAnnotation and the AccInterface bits + return accessFlags & ~(ClassFileConstants.AccAbstract | ClassFileConstants.AccInterface | ClassFileConstants.AccAnnotation); + } else if (isInterface()) { + ReferenceBinding referenceBinding = (ReferenceBinding) this.binding; + final int accessFlags = referenceBinding.getAccessFlags() & VALID_MODIFIERS; + // clear the AccAbstract and the AccInterface bits + return accessFlags & ~(ClassFileConstants.AccAbstract | ClassFileConstants.AccInterface); + } else if (isEnum()) { + ReferenceBinding referenceBinding = (ReferenceBinding) this.binding; + final int accessFlags = referenceBinding.getAccessFlags() & VALID_MODIFIERS; + // clear the AccEnum bits + return accessFlags & ~ClassFileConstants.AccEnum; + } else { + return Modifier.NONE; + } + } + + public String getName() { + StringBuffer buffer; + switch (this.binding.kind()) { + + case Binding.WILDCARD_TYPE : + case Binding.INTERSECTION_TYPE: + WildcardBinding wildcardBinding = (WildcardBinding) this.binding; + buffer = new StringBuffer(); + buffer.append(TypeConstants.WILDCARD_NAME); + if (wildcardBinding.bound != null) { + switch(wildcardBinding.boundKind) { + case Wildcard.SUPER : + buffer.append(TypeConstants.WILDCARD_SUPER); + break; + case Wildcard.EXTENDS : + buffer.append(TypeConstants.WILDCARD_EXTENDS); + } + buffer.append(getBound().getName()); + } + return String.valueOf(buffer); + + case Binding.TYPE_PARAMETER : + if (isCapture()) { + return NO_NAME; + } + TypeVariableBinding typeVariableBinding = (TypeVariableBinding) this.binding; + return new String(typeVariableBinding.sourceName); + + case Binding.PARAMETERIZED_TYPE : + ParameterizedTypeBinding parameterizedTypeBinding = (ParameterizedTypeBinding) this.binding; + buffer = new StringBuffer(); + buffer.append(parameterizedTypeBinding.sourceName()); + ITypeBinding[] tArguments = getTypeArguments(); + final int typeArgumentsLength = tArguments.length; + if (typeArgumentsLength != 0) { + buffer.append('<'); + for (int i = 0; i < typeArgumentsLength; i++) { + if (i > 0) { + buffer.append(','); + } + buffer.append(tArguments[i].getName()); + } + buffer.append('>'); + } + return String.valueOf(buffer); + + case Binding.RAW_TYPE : + return getTypeDeclaration().getName(); + + case Binding.ARRAY_TYPE : + ITypeBinding elementType = getElementType(); + if (elementType.isLocal() || elementType.isAnonymous() || elementType.isCapture()) { + return NO_NAME; + } + int dimensions = getDimensions(); + char[] brackets = new char[dimensions * 2]; + for (int i = dimensions * 2 - 1; i >= 0; i -= 2) { + brackets[i] = ']'; + brackets[i - 1] = '['; + } + buffer = new StringBuffer(elementType.getName()); + buffer.append(brackets); + return String.valueOf(buffer); + + default : + if (isPrimitive() || isNullType()) { + BaseTypeBinding baseTypeBinding = (BaseTypeBinding) this.binding; + return new String(baseTypeBinding.simpleName); + } + if (isAnonymous()) { + return NO_NAME; + } + return new String(this.binding.sourceName()); + } + } + + /* + * @see ITypeBinding#getPackage() + */ + public IPackageBinding getPackage() { + switch (this.binding.kind()) { + case Binding.BASE_TYPE : + case Binding.ARRAY_TYPE : + case Binding.TYPE_PARAMETER : // includes capture scenario + case Binding.WILDCARD_TYPE : + case Binding.INTERSECTION_TYPE: + return null; + } + ReferenceBinding referenceBinding = (ReferenceBinding) this.binding; + return this.resolver.getPackageBinding(referenceBinding.getPackage()); + } + + /** + * @see org.eclipse.jdt.core.dom.ITypeBinding#getQualifiedName() + */ + public String getQualifiedName() { + StringBuffer buffer; + switch (this.binding.kind()) { + + case Binding.WILDCARD_TYPE : + case Binding.INTERSECTION_TYPE: + WildcardBinding wildcardBinding = (WildcardBinding) this.binding; + buffer = new StringBuffer(); + buffer.append(TypeConstants.WILDCARD_NAME); + final ITypeBinding bound = getBound(); + if (bound != null) { + switch(wildcardBinding.boundKind) { + case Wildcard.SUPER : + buffer.append(TypeConstants.WILDCARD_SUPER); + break; + case Wildcard.EXTENDS : + buffer.append(TypeConstants.WILDCARD_EXTENDS); + } + buffer.append(bound.getQualifiedName()); + } + return String.valueOf(buffer); + + case Binding.RAW_TYPE : + return getTypeDeclaration().getQualifiedName(); + + case Binding.ARRAY_TYPE : + ITypeBinding elementType = getElementType(); + if (elementType.isLocal() || elementType.isAnonymous() || elementType.isCapture()) { + return elementType.getQualifiedName(); + } + final int dimensions = getDimensions(); + char[] brackets = new char[dimensions * 2]; + for (int i = dimensions * 2 - 1; i >= 0; i -= 2) { + brackets[i] = ']'; + brackets[i - 1] = '['; + } + buffer = new StringBuffer(elementType.getQualifiedName()); + buffer.append(brackets); + return String.valueOf(buffer); + + case Binding.TYPE_PARAMETER : + if (isCapture()) { + return NO_NAME; + } + TypeVariableBinding typeVariableBinding = (TypeVariableBinding) this.binding; + return new String(typeVariableBinding.sourceName); + + case Binding.PARAMETERIZED_TYPE : + if (this.binding.isLocalType()) { + return NO_NAME; + } + buffer = new StringBuffer(); + if (isMember()) { + buffer + .append(getDeclaringClass().getQualifiedName()) + .append('.'); + ParameterizedTypeBinding parameterizedTypeBinding = (ParameterizedTypeBinding) this.binding; + buffer.append(parameterizedTypeBinding.sourceName()); + ITypeBinding[] tArguments = getTypeArguments(); + final int typeArgumentsLength = tArguments.length; + if (typeArgumentsLength != 0) { + buffer.append('<'); + for (int i = 0; i < typeArgumentsLength; i++) { + if (i > 0) { + buffer.append(','); + } + buffer.append(tArguments[i].getQualifiedName()); + } + buffer.append('>'); + } + return String.valueOf(buffer); + } + buffer.append(getTypeDeclaration().getQualifiedName()); + ITypeBinding[] tArguments = getTypeArguments(); + final int typeArgumentsLength = tArguments.length; + if (typeArgumentsLength != 0) { + buffer.append('<'); + for (int i = 0; i < typeArgumentsLength; i++) { + if (i > 0) { + buffer.append(','); + } + buffer.append(tArguments[i].getQualifiedName()); + } + buffer.append('>'); + } + return String.valueOf(buffer); + default : + if (isAnonymous() || this.binding.isLocalType()) { + return NO_NAME; + } + if (isPrimitive() || isNullType()) { + BaseTypeBinding baseTypeBinding = (BaseTypeBinding) this.binding; + return new String(baseTypeBinding.simpleName); + } + if (isMember()) { + buffer = new StringBuffer(); + buffer + .append(getDeclaringClass().getQualifiedName()) + .append('.'); + buffer.append(getName()); + return String.valueOf(buffer); + } + PackageBinding packageBinding = this.binding.getPackage(); + buffer = new StringBuffer(); + if (packageBinding != null && packageBinding.compoundName != CharOperation.NO_CHAR_CHAR) { + buffer.append(CharOperation.concatWith(packageBinding.compoundName, '.')).append('.'); + } + buffer.append(getName()); + return String.valueOf(buffer); + } + } + + +//{ObjectTeams: uniform handling of regular types names and anchored role type names: + public String getOptimalName() { + if (binding instanceof ReferenceBinding) + return new String(((ReferenceBinding)binding).optimalName()); + return getQualifiedName(); + } +// SH} + +//{ObjectTeams: tsuper types for roles via role model: + public ITypeBinding[] getSuperRoles() + { + if (this.binding == null || !this.isRole()) + { + return null; + } + if (binding instanceof ReferenceBinding) + { + RoleModel roleModel = ((ReferenceBinding)binding).roleModel; + ReferenceBinding[] tsuperRefs = roleModel.getTSuperRoleBindings(); + int length = tsuperRefs.length; + ITypeBinding[] superRoles = new ITypeBinding[length]; + for (int i = 0; i < length; i++) + { + superRoles[i] = this.resolver.getTypeBinding(tsuperRefs[i]); + } + return superRoles; + } + return null; + } +// mkr} + + /* + * @see ITypeBinding#getSuperclass() + */ + public synchronized ITypeBinding getSuperclass() { + if (this.binding == null) + return null; + switch (this.binding.kind()) { + case Binding.ARRAY_TYPE : + case Binding.BASE_TYPE : + return null; + default: + // no superclass for interface types (interface | annotation type) + if (this.binding.isInterface()) + return null; + } + ReferenceBinding superclass = null; + try { + superclass = ((ReferenceBinding)this.binding).superclass(); + } catch (RuntimeException e) { + /* in case a method cannot be resolvable due to missing jars on the classpath + * see https://bugs.eclipse.org/bugs/show_bug.cgi?id=57871 + * https://bugs.eclipse.org/bugs/show_bug.cgi?id=63550 + * https://bugs.eclipse.org/bugs/show_bug.cgi?id=64299 + */ + org.eclipse.jdt.internal.core.util.Util.log(e, "Could not retrieve superclass"); //$NON-NLS-1$ + return this.resolver.resolveWellKnownType("java.lang.Object"); //$NON-NLS-1$ + } + if (superclass == null) { + return null; + } + return this.resolver.getTypeBinding(superclass); + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#getTypeArguments() + */ + public ITypeBinding[] getTypeArguments() { + if (this.typeArguments != null) { + return this.typeArguments; + } + if (this.binding.isParameterizedTypeWithActualArguments()) { + ParameterizedTypeBinding parameterizedTypeBinding = (ParameterizedTypeBinding) this.binding; + final org.eclipse.jdt.internal.compiler.lookup.TypeBinding[] arguments = parameterizedTypeBinding.arguments; + int argumentsLength = arguments.length; + ITypeBinding[] newTypeArguments = new ITypeBinding[argumentsLength]; + for (int i = 0; i < argumentsLength; i++) { + ITypeBinding typeBinding = this.resolver.getTypeBinding(arguments[i]); + if (typeBinding == null) { + return this.typeArguments = NO_TYPE_BINDINGS; + } + newTypeArguments[i] = typeBinding; + } + return this.typeArguments = newTypeArguments; + } + return this.typeArguments = NO_TYPE_BINDINGS; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#getTypeBounds() + */ + public ITypeBinding[] getTypeBounds() { + if (this.bounds != null) { + return this.bounds; + } + if (this.binding instanceof TypeVariableBinding) { + TypeVariableBinding typeVariableBinding = (TypeVariableBinding) this.binding; + ReferenceBinding varSuperclass = typeVariableBinding.superclass(); + org.eclipse.jdt.internal.compiler.lookup.TypeBinding firstClassOrArrayBound = typeVariableBinding.firstBound; + int boundsLength = 0; + if (firstClassOrArrayBound != null) { + if (firstClassOrArrayBound == varSuperclass) { + boundsLength++; + } else if (firstClassOrArrayBound.isArrayType()) { // capture of ? extends/super arrayType + boundsLength++; + } else { + firstClassOrArrayBound = null; + } + } + ReferenceBinding[] superinterfaces = typeVariableBinding.superInterfaces(); + int superinterfacesLength = 0; + if (superinterfaces != null) { + superinterfacesLength = superinterfaces.length; + boundsLength += superinterfacesLength; + } + if (boundsLength != 0) { + ITypeBinding[] typeBounds = new ITypeBinding[boundsLength]; + int boundsIndex = 0; + if (firstClassOrArrayBound != null) { + ITypeBinding typeBinding = this.resolver.getTypeBinding(firstClassOrArrayBound); + if (typeBinding == null) { + return this.bounds = NO_TYPE_BINDINGS; + } + typeBounds[boundsIndex++] = typeBinding; + } + if (superinterfaces != null) { + for (int i = 0; i < superinterfacesLength; i++, boundsIndex++) { + ITypeBinding typeBinding = this.resolver.getTypeBinding(superinterfaces[i]); + if (typeBinding == null) { + return this.bounds = NO_TYPE_BINDINGS; + } + typeBounds[boundsIndex] = typeBinding; + } + } + return this.bounds = typeBounds; + } + } + return this.bounds = NO_TYPE_BINDINGS; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#getTypeParameters() + */ + public ITypeBinding[] getTypeParameters() { + if (this.typeParameters != null) { + return this.typeParameters; + } + switch(this.binding.kind()) { + case Binding.RAW_TYPE : + case Binding.PARAMETERIZED_TYPE : + return this.typeParameters = NO_TYPE_BINDINGS; + } + TypeVariableBinding[] typeVariableBindings = this.binding.typeVariables(); + int typeVariableBindingsLength = typeVariableBindings == null ? 0 : typeVariableBindings.length; + if (typeVariableBindingsLength != 0) { + ITypeBinding[] newTypeParameters = new ITypeBinding[typeVariableBindingsLength]; + for (int i = 0; i < typeVariableBindingsLength; i++) { + ITypeBinding typeBinding = this.resolver.getTypeBinding(typeVariableBindings[i]); + if (typeBinding == null) { + return this.typeParameters = NO_TYPE_BINDINGS; + } + newTypeParameters[i] = typeBinding; + } + return this.typeParameters = newTypeParameters; + } + return this.typeParameters = NO_TYPE_BINDINGS; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#getWildcard() + * @since 3.1 + */ + public ITypeBinding getWildcard() { + if (this.binding instanceof CaptureBinding) { + CaptureBinding captureBinding = (CaptureBinding) this.binding; + return this.resolver.getTypeBinding(captureBinding.wildcard); + } + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#isGenericType() + * @since 3.1 + */ + public boolean isGenericType() { + // equivalent to return getTypeParameters().length > 0; + if (isRawType()) { + return false; + } + TypeVariableBinding[] typeVariableBindings = this.binding.typeVariables(); + return (typeVariableBindings != null && typeVariableBindings.length > 0); + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#isAnnotation() + */ + public boolean isAnnotation() { + return this.binding.isAnnotationType(); + } + + /* + * @see ITypeBinding#isAnonymous() + */ + public boolean isAnonymous() { + if (isClass() || isInterface() || isEnum()) { + ReferenceBinding referenceBinding = (ReferenceBinding) this.binding; + return referenceBinding.isAnonymousType(); + } + return false; + } + + /* + * @see ITypeBinding#isArray() + */ + public boolean isArray() { + return this.binding.isArrayType(); + } + + /* (non-Javadoc) + * @see ITypeBinding#isAssignmentCompatible(ITypeBinding) + */ + public boolean isAssignmentCompatible(ITypeBinding type) { + try { + if (this == type) return true; + if (!(type instanceof TypeBinding)) return false; + TypeBinding other = (TypeBinding) type; + Scope scope = this.resolver.scope(); + if (scope == null) return false; + return this.binding.isCompatibleWith(other.binding) || scope.isBoxingCompatibleWith(this.binding, other.binding); + } catch (AbortCompilation e) { + // don't surface internal exception to clients + // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=143013 + return false; + } + } + + /* (non-Javadoc) + * @see ITypeBinding#isCapture() + */ + public boolean isCapture() { + return this.binding.isCapture(); + } + + /* (non-Javadoc) + * @see ITypeBinding#isCastCompatible(ITypeBinding) + */ + public boolean isCastCompatible(ITypeBinding type) { + try { + Expression expression = new Expression() { + public StringBuffer printExpression(int indent,StringBuffer output) { + return null; + } + }; + Scope scope = this.resolver.scope(); + if (scope == null) return false; + if (!(type instanceof TypeBinding)) return false; + org.eclipse.jdt.internal.compiler.lookup.TypeBinding expressionType = ((TypeBinding) type).binding; + // simulate capture in case checked binding did not properly get extracted from a reference + expressionType = expressionType.capture(scope, 0); + return expression.checkCastTypesCompatibility(scope, this.binding, expressionType, null); + } catch (AbortCompilation e) { + // don't surface internal exception to clients + // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=143013 + return false; + } + } + + /* + * @see ITypeBinding#isClass() + */ + public boolean isClass() { + switch (this.binding.kind()) { + case Binding.TYPE_PARAMETER : + case Binding.WILDCARD_TYPE : + case Binding.INTERSECTION_TYPE : + return false; + } + return this.binding.isClass(); + } + + /* + * @see IBinding#isDeprecated() + */ + public boolean isDeprecated() { + if (isClass() || isInterface() || isEnum()) { + ReferenceBinding referenceBinding = (ReferenceBinding) this.binding; + return referenceBinding.isDeprecated(); + } + return false; + } + + /* (non-Javadoc) + * @see ITypeBinding#isEnum() + */ + public boolean isEnum() { + return this.binding.isEnum(); + } + + /* + * @see IBinding#isEqualTo(Binding) + * @since 3.1 + */ + public boolean isEqualTo(IBinding other) { + if (other == this) { + // identical binding - equal (key or no key) + return true; + } + if (other == null) { + // other binding missing + return false; + } + if (!(other instanceof TypeBinding)) { + return false; + } + org.eclipse.jdt.internal.compiler.lookup.TypeBinding otherBinding = ((TypeBinding) other).binding; + // check return type + return BindingComparator.isEqual(this.binding, otherBinding); + } + + /* + * @see ITypeBinding#isFromSource() + */ + public boolean isFromSource() { + if (isClass() || isInterface() || isEnum()) { + ReferenceBinding referenceBinding = (ReferenceBinding) this.binding; + if (referenceBinding.isRawType()) { + return !((RawTypeBinding) referenceBinding).genericType().isBinaryBinding(); + } else if (referenceBinding.isParameterizedType()) { + ParameterizedTypeBinding parameterizedTypeBinding = (ParameterizedTypeBinding) referenceBinding; + org.eclipse.jdt.internal.compiler.lookup.TypeBinding erasure = parameterizedTypeBinding.erasure(); + if (erasure instanceof ReferenceBinding) { + return !((ReferenceBinding) erasure).isBinaryBinding(); + } + return false; + } else { + return !referenceBinding.isBinaryBinding(); + } + } else if (isTypeVariable()) { + final TypeVariableBinding typeVariableBinding = (TypeVariableBinding) this.binding; + final Binding declaringElement = typeVariableBinding.declaringElement; + if (declaringElement instanceof MethodBinding) { + MethodBinding methodBinding = (MethodBinding) declaringElement; + return !methodBinding.declaringClass.isBinaryBinding(); + } else { + final org.eclipse.jdt.internal.compiler.lookup.TypeBinding typeBinding = (org.eclipse.jdt.internal.compiler.lookup.TypeBinding) declaringElement; + if (typeBinding instanceof ReferenceBinding) { + return !((ReferenceBinding) typeBinding).isBinaryBinding(); + } else if (typeBinding instanceof ArrayBinding) { + final ArrayBinding arrayBinding = (ArrayBinding) typeBinding; + final org.eclipse.jdt.internal.compiler.lookup.TypeBinding leafComponentType = arrayBinding.leafComponentType; + if (leafComponentType instanceof ReferenceBinding) { + return !((ReferenceBinding) leafComponentType).isBinaryBinding(); + } + } + } + + } else if (isCapture()) { + CaptureBinding captureBinding = (CaptureBinding) this.binding; + return !captureBinding.sourceType.isBinaryBinding(); + } + return false; + } + + /* + * @see ITypeBinding#isInterface() + */ + public boolean isInterface() { + switch (this.binding.kind()) { + case Binding.TYPE_PARAMETER : + case Binding.WILDCARD_TYPE : + case Binding.INTERSECTION_TYPE : + return false; + } + return this.binding.isInterface(); + } + +//{ObjectTeams: ira + /* + * @see ITypeBinding#isTeam() + */ + public boolean isTeam() { + return this.binding.isTeam(); + } + + /* + * @see ITypeBinding#isRole() + */ + public boolean isRole() { + return this.binding.isRole(); + } + + /* + * @see ITypeBinding#isClassPartOf() + */ + public boolean isClassPartOf (ITypeBinding other) { + if (this.binding == null || !this.binding.isRole()) + return false; + RoleModel roleModel = ((ReferenceBinding)this.binding).roleModel; + if (roleModel == null) + return false; + org.eclipse.jdt.internal.compiler.lookup.TypeBinding otherBinding = (other instanceof RecoveredTypeBinding) + ? ((RecoveredTypeBinding)other).getResolvedBinding() + : ((TypeBinding)other).binding; + return roleModel.getInterfacePartBinding() == otherBinding; + } + public boolean isSynthRoleIfc() { + if (this.binding == null || !this.binding.isRole()) + return false; + return ((ReferenceBinding)this.binding).isSynthInterface(); + } + /* + * @see ITypeBinding#getIfcPart() + */ + public ITypeBinding getIfcPart() { + if (isInterface()) + return this; + if (!isRole()) + return null; + ReferenceBinding roleBinding = (ReferenceBinding) this.binding; + ReferenceBinding ifcPart = roleBinding.getRealType(); + if (ifcPart == null) + return null; + return this.resolver.getTypeBinding(ifcPart); + } + /* + * @see ITypeBinding#getBaseClass() + */ + public ITypeBinding getBaseClass() { + if (! this.binding.isRole()) + return null; + MemberTypeBinding roleBinding = (MemberTypeBinding) this.binding; + ReferenceBinding baseclass = roleBinding.baseclass(); + if (baseclass == null) { + return null; + } + return this.resolver.getTypeBinding(baseclass); + } +// ira+SH} + + /* + * @see ITypeBinding#isLocal() + */ + public boolean isLocal() { + if (isClass() || isInterface() || isEnum()) { + ReferenceBinding referenceBinding = (ReferenceBinding) this.binding; + return referenceBinding.isLocalType() && !referenceBinding.isMemberType(); + } + return false; + } + + /* + * @see ITypeBinding#isMember() + */ + public boolean isMember() { + if (isClass() || isInterface() || isEnum()) { + ReferenceBinding referenceBinding = (ReferenceBinding) this.binding; + return referenceBinding.isMemberType(); + } + return false; + } + + /* + * @see ITypeBinding#isNested() + */ + public boolean isNested() { + if (isClass() || isInterface() || isEnum()) { + ReferenceBinding referenceBinding = (ReferenceBinding) this.binding; + return referenceBinding.isNestedType(); + } + return false; + } + + /** + * @see ITypeBinding#isNullType() + */ + public boolean isNullType() { + return this.binding == org.eclipse.jdt.internal.compiler.lookup.TypeBinding.NULL; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#isParameterizedType() + */ + public boolean isParameterizedType() { + return this.binding.isParameterizedTypeWithActualArguments(); + } + +//{ObjectTeams: + public boolean isDependentType(boolean onlyRelevant) { + if (onlyRelevant) + return RoleTypeBinding.isRoleWithExplicitAnchor(this.binding); + return DependentTypeBinding.isDependentType(this.binding); + } + + public String[] getAnchorPath() { + if (!DependentTypeBinding.isDependentType(this.binding)) + return new String[0]; + + return getBestNamePath((DependentTypeBinding)this.binding); + } + + static String[] getBestNamePath(DependentTypeBinding dType) { + ITeamAnchor[] path = dType.getAnchor().getBestNamePath(); + String[] segments = new String[path.length]; + for (int i = 0; i < path.length; i++) { + segments[i] = new String(path[i].internalName()); + } + return segments; + } +// SH} + /* + * @see ITypeBinding#isPrimitive() + */ + public boolean isPrimitive() { + return !isNullType() && this.binding.isBaseType(); + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#isRawType() + */ + public boolean isRawType() { + return this.binding.isRawType(); + } + + /* (non-Javadoc) + * @see IBinding#isRecovered() + */ + public boolean isRecovered() { + return (this.binding.tagBits & TagBits.HasMissingType) != 0; + } + + /* (non-Javadoc) + * @see ITypeBinding#isSubTypeCompatible(ITypeBinding) + */ + public boolean isSubTypeCompatible(ITypeBinding type) { + try { + if (this == type) return true; + if (this.binding.isBaseType()) return false; + if (!(type instanceof TypeBinding)) return false; + TypeBinding other = (TypeBinding) type; + if (other.binding.isBaseType()) return false; + return this.binding.isCompatibleWith(other.binding); + } catch (AbortCompilation e) { + // don't surface internal exception to clients + // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=143013 + return false; + } + } + + /** + * @see IBinding#isSynthetic() + */ + public boolean isSynthetic() { + return false; + } + + /* + * @see ITypeBinding#isTopLevel() + */ + public boolean isTopLevel() { + if (isClass() || isInterface() || isEnum()) { + ReferenceBinding referenceBinding = (ReferenceBinding) this.binding; + return !referenceBinding.isNestedType(); + } + return false; + } + + /* + * @see ITypeBinding#isTypeVariable() + */ + public boolean isTypeVariable() { + return this.binding.isTypeVariable() && !this.binding.isCapture(); + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#isUpperbound() + */ + public boolean isUpperbound() { + switch (this.binding.kind()) { + case Binding.WILDCARD_TYPE : + return ((WildcardBinding) this.binding).boundKind == Wildcard.EXTENDS; + case Binding.INTERSECTION_TYPE : + return true; + } + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ITypeBinding#isWildcardType() + */ + public boolean isWildcardType() { + return this.binding.isWildcard(); + } + +//{ObjectTeams: additional queries based on this.binding: + public IMethodMappingBinding[] getResolvedMethodMappings() { + List<IMethodMappingBinding> mappings = new ArrayList<IMethodMappingBinding>(); + if (this.isRole()) { + org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding roleBinding + = (org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding)this.binding; + if (roleBinding.callinCallouts != null) { + for (CallinCalloutBinding mapping : roleBinding.callinCallouts) { + mappings.add(this.resolver.getMethodMappingBinding(mapping)); + } + } + } + IMethodMappingBinding[] result = new IMethodMappingBinding[mappings.size()]; + if (!mappings.isEmpty()) + mappings.toArray(result); + return result; + } +// SH} + /* + * For debugging purpose only. + * @see java.lang.Object#toString() + */ + public String toString() { + return this.binding.toString(); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeDeclaration.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeDeclaration.java new file mode 100644 index 000000000..b72a70ff6 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeDeclaration.java @@ -0,0 +1,1106 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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 + * $Id: TypeDeclaration.java 23123 2009-12-01 23:57:01Z stephan $ + * + * Contributors: + * IBM Corporation - initial API and implementation + * Fraunhofer FIRST - extended API and implementation + * Technical University Berlin - extended API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * Type declaration AST node type. A type declaration + * is the union of a class declaration and an interface declaration. + * For JLS2: + * <pre> + * TypeDeclaration: + * ClassDeclaration + * InterfaceDeclaration + * ClassDeclaration: + * [ Javadoc ] { Modifier } <b>class</b> Identifier + * [ <b>extends</b> Type] + * [ <b>implements</b> Type { <b>,</b> Type } ] + * <b>{</b> { ClassBodyDeclaration | <b>;</b> } <b>}</b> + * InterfaceDeclaration: + * [ Javadoc ] { Modifier } <b>interface</b> Identifier + * [ <b>extends</b> Type { <b>,</b> Type } ] + * <b>{</b> { InterfaceBodyDeclaration | <b>;</b> } <b>}</b> + * </pre> + * For JLS3, type parameters and reified modifiers + * (and annotations) were added, and the superclass type name and superinterface + * types names are generalized to type so that parameterized types can be + * referenced: + * <pre> + * TypeDeclaration: + * ClassDeclaration + * InterfaceDeclaration + * ClassDeclaration: + * [ Javadoc ] { ExtendedModifier } <b>class</b> Identifier + * [ <b><</b> TypeParameter { <b>,</b> TypeParameter } <b>></b> ] + * [ <b>extends</b> Type ] + * [ <b>implements</b> Type { <b>,</b> Type } ] + * <b>{</b> { ClassBodyDeclaration | <b>;</b> } <b>}</b> + * InterfaceDeclaration: + * [ Javadoc ] { ExtendedModifier } <b>interface</b> Identifier + * [ <b><</b> TypeParameter { <b>,</b> TypeParameter } <b>></b> ] + * [ <b>extends</b> Type { <b>,</b> Type } ] + * <b>{</b> { InterfaceBodyDeclaration | <b>;</b> } <b>}</b> + * </pre> + * <p> + * When a Javadoc comment is present, the source + * range begins with the first character of the "/**" comment delimiter. + * When there is no Javadoc comment, the source range begins with the first + * character of the first modifier or annotation (if any), or the + * first character of the "class" or "interface" keyword (if no + * modifiers or annotations). The source range extends through the last character of the "}" + * token following the body declarations. + * </p> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class TypeDeclaration extends AbstractTypeDeclaration { + + /** + * The "javadoc" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor JAVADOC_PROPERTY = + internalJavadocPropertyFactory(TypeDeclaration.class); + + /** + * The "modifiers" structural property of this node type (JLS2 API only). + * @since 3.0 + */ + public static final SimplePropertyDescriptor MODIFIERS_PROPERTY = + internalModifiersPropertyFactory(TypeDeclaration.class); + + /** + * The "modifiers" structural property of this node type (added in JLS3 API). + * @since 3.1 + */ + public static final ChildListPropertyDescriptor MODIFIERS2_PROPERTY = + internalModifiers2PropertyFactory(TypeDeclaration.class); + + /** + * The "interface" structural property of this node type. + * @since 3.0 + */ + public static final SimplePropertyDescriptor INTERFACE_PROPERTY = + new SimplePropertyDescriptor(TypeDeclaration.class, "interface", boolean.class, MANDATORY); //$NON-NLS-1$ + +//{ObjectTeams: OT-specific properties + /** + * The "team" structural property of this node type. + */ + public static final SimplePropertyDescriptor TEAM_PROPERTY = + new SimplePropertyDescriptor(TypeDeclaration.class, "team", boolean.class, MANDATORY); //$NON-NLS-1$ + + /** + * The "role" structural property of this node type. + */ + public static final SimplePropertyDescriptor ROLE_PROPERTY = + new SimplePropertyDescriptor(TypeDeclaration.class, "role", boolean.class, MANDATORY); //$NON-NLS-1$ + + /** + * The "precedence" structural property. + */ + public static final ChildListPropertyDescriptor PRECEDENCE_PROPERTY = + new ChildListPropertyDescriptor(TypeDeclaration.class, "precedence", PrecedenceDeclaration.class, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "guardPredicate" structural property of this node type. + * @since 0.9.25 + */ + public static final ChildPropertyDescriptor GUARD_PROPERTY = + new ChildPropertyDescriptor(TypeDeclaration.class, "guardPredicate", GuardPredicateDeclaration.class, OPTIONAL, NO_CYCLE_RISK); //$NON-NLS-1$ +//gbr+SH} + + /** + * The "name" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor NAME_PROPERTY = + internalNamePropertyFactory(TypeDeclaration.class); + + /** + * The "superclass" structural property of this node type (JLS2 API only). + * @since 3.0 + */ + public static final ChildPropertyDescriptor SUPERCLASS_PROPERTY = + new ChildPropertyDescriptor(TypeDeclaration.class, "superclass", Name.class, OPTIONAL, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "superInterfaces" structural property of this node type (JLS2 API only). + * @since 3.0 + */ + public static final ChildListPropertyDescriptor SUPER_INTERFACES_PROPERTY = + new ChildListPropertyDescriptor(TypeDeclaration.class, "superInterfaces", Name.class, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "superclassType" structural property of this node type (added in JLS3 API). + * @since 3.1 + */ + public static final ChildPropertyDescriptor SUPERCLASS_TYPE_PROPERTY = + new ChildPropertyDescriptor(TypeDeclaration.class, "superclassType", Type.class, OPTIONAL, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "superInterfaceTypes" structural property of this node type (added in JLS3 API). + * @since 3.1 + */ + public static final ChildListPropertyDescriptor SUPER_INTERFACE_TYPES_PROPERTY = + new ChildListPropertyDescriptor(TypeDeclaration.class, "superInterfaceTypes", Type.class, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "typeParameters" structural property of this node type (added in JLS3 API). + * @since 3.1 + */ + public static final ChildListPropertyDescriptor TYPE_PARAMETERS_PROPERTY = + new ChildListPropertyDescriptor(TypeDeclaration.class, "typeParameters", TypeParameter.class, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "bodyDeclarations" structural property of this node type (added in JLS3 API). + * @since 3.0 + */ + public static final ChildListPropertyDescriptor BODY_DECLARATIONS_PROPERTY = + internalBodyDeclarationPropertyFactory(TypeDeclaration.class); + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + * @since 3.0 + */ + private static final List PROPERTY_DESCRIPTORS_2_0; + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + * @since 3.1 + */ + private static final List PROPERTY_DESCRIPTORS_3_0; + + static { + List propertyList = new ArrayList(12); + createPropertyList(TypeDeclaration.class, propertyList); + addProperty(JAVADOC_PROPERTY, propertyList); + addProperty(MODIFIERS_PROPERTY, propertyList); + addProperty(INTERFACE_PROPERTY, propertyList); +//{ObjectTeams: OT-specific properties added + addProperty(TEAM_PROPERTY, propertyList); + addProperty(ROLE_PROPERTY, propertyList); + addProperty(PRECEDENCE_PROPERTY, propertyList); + addProperty(GUARD_PROPERTY, propertyList); +//gbr+SH} + addProperty(NAME_PROPERTY, propertyList); + addProperty(SUPERCLASS_PROPERTY, propertyList); + addProperty(SUPER_INTERFACES_PROPERTY, propertyList); + addProperty(BODY_DECLARATIONS_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS_2_0 = reapPropertyList(propertyList); + + propertyList = new ArrayList(13); + createPropertyList(TypeDeclaration.class, propertyList); + addProperty(JAVADOC_PROPERTY, propertyList); + addProperty(MODIFIERS2_PROPERTY, propertyList); + addProperty(INTERFACE_PROPERTY, propertyList); +//{ObjectTeams: OT-specific properties added + addProperty(TEAM_PROPERTY, propertyList); + addProperty(ROLE_PROPERTY, propertyList); + addProperty(PRECEDENCE_PROPERTY, propertyList); + addProperty(GUARD_PROPERTY, propertyList); +//gbr+SH} + addProperty(NAME_PROPERTY, propertyList); + addProperty(TYPE_PARAMETERS_PROPERTY, propertyList); + addProperty(SUPERCLASS_TYPE_PROPERTY, propertyList); + addProperty(SUPER_INTERFACE_TYPES_PROPERTY, propertyList); + addProperty(BODY_DECLARATIONS_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS_3_0 = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + if (apiLevel == AST.JLS2_INTERNAL) { + return PROPERTY_DESCRIPTORS_2_0; + } else { + return PROPERTY_DESCRIPTORS_3_0; + } + } + + /** + * <code>true</code> for an interface, <code>false</code> for a class. + * Defaults to class. + */ +//{ObjectTeams: avoid private to allow access from RoleTypeDeclaration without duplicating this field +/* orig: + private boolean isInterface = false; + :giro */ + boolean isInterface = false; +// SH} + +//{ObjectTeams: OT-specific fields added + /** + * <code>true</code> for a team, <code>false</code> for a class. + * Defaults to class. + */ + boolean _isTeam = false; + + /** + * <code>true</code> for a role, <code>false</code> for a class. + * Defaults to class. + */ + boolean _isRole = false; + + ASTNode.NodeList _precedences = new ASTNode.NodeList(PRECEDENCE_PROPERTY); + + GuardPredicateDeclaration optionalGuardPredicate = null; +//gbr} + + /** + * The type paramters (element type: <code>TypeParameter</code>). + * Null in JLS2. Added in JLS3; defaults to an empty list + * (see constructor). + * @since 3.1 + */ +//{ObjectTeams: avoid private to allow access from RoleTypeDeclaration without duplicating this field +/* orig: + private ASTNode.NodeList typeParameters = null; + :giro */ + ASTNode.NodeList typeParameters = null; +// SH} + /** + * The optional superclass name; <code>null</code> if none. + * Defaults to none. Note that this field is not used for + * interface declarations. Not used in 3.0. + */ +//{ObjectTeams: avoid private to allow access from RoleTypeDeclaration without duplicating this field +/* orig: + private Name optionalSuperclassName = null; + :giro */ + Name optionalSuperclassName = null; +// SH} + /** + * The superinterface names (element type: <code>Name</code>). + * JLS2 only; defaults to an empty list. Not used in JLS3. + * (see constructor). + * + */ +//{ObjectTeams: avoid private to allow access from RoleTypeDeclaration without duplicating this field +/* orig: + private ASTNode.NodeList superInterfaceNames = null; + :giro */ + ASTNode.NodeList superInterfaceNames = null; +// SH} + /** + * The optional superclass type; <code>null</code> if none. + * Defaults to none. Note that this field is not used for + * interface declarations. Null in JLS2. Added in JLS3. + * @since 3.1 + */ +//{ObjectTeams: avoid private to allow access from RoleTypeDeclaration without duplicating this field +/* orig: + private Type optionalSuperclassType = null; + :giro */ + Type optionalSuperclassType = null; +// SH} + /** + * The superinterface types (element type: <code>Type</code>). + * Null in JLS2. Added in JLS3; defaults to an empty list + * (see constructor). + * @since 3.1 + */ +//{ObjectTeams: avoid private to allow access from RoleTypeDeclaration without duplicating this field +/* orig: + private ASTNode.NodeList superInterfaceTypes = null; + :giro */ + ASTNode.NodeList superInterfaceTypes = null; +// SH} + /** + * Creates a new AST node for a type declaration owned by the given + * AST. By default, the type declaration is for a class of an + * unspecified, but legal, name; no modifiers; no javadoc; + * no type parameters; no superclass or superinterfaces; and an empty list + * of body declarations. + * <p> + * N.B. This constructor is package-private; all subclasses must be + * declared in the same package; clients are unable to declare + * additional subclasses. + * </p> + * + * @param ast the AST that is to own this node + */ + TypeDeclaration(AST ast) { + super(ast); + if (ast.apiLevel == AST.JLS2_INTERNAL) { + this.superInterfaceNames = new ASTNode.NodeList(SUPER_INTERFACES_PROPERTY); + } + if (ast.apiLevel >= AST.JLS3) { + this.typeParameters = new ASTNode.NodeList(TYPE_PARAMETERS_PROPERTY); + this.superInterfaceTypes = new ASTNode.NodeList(SUPER_INTERFACE_TYPES_PROPERTY); + } + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + * @since 3.0 + */ +//{ObjectTeams: RoleTypeDeclaration can not inherit all methods, so final modifier removed + /*final*/ List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } +//ike} + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ +// {ObjectTeams: RoleTypeDeclaration can not inherit all methods, so final modifier removed + /*final*/ int internalGetSetIntProperty(SimplePropertyDescriptor property, boolean get, int value) { +// ike} + if (property == MODIFIERS_PROPERTY) { + if (get) { + return getModifiers(); + } else { + internalSetModifiers(value); + return 0; + } + } + // allow default implementation to flag the error + return super.internalGetSetIntProperty(property, get, value); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ +// {ObjectTeams: RoleTypeDeclaration can not inherit all methods, so final modifier removed + /*final*/ boolean internalGetSetBooleanProperty(SimplePropertyDescriptor property, boolean get, boolean value) { +// ike} + if (property == INTERFACE_PROPERTY) { + if (get) { + return isInterface(); + } else { + setInterface(value); + return false; + } + } +//{ObjectTeams: cases for OT-specific properties added + if (property == TEAM_PROPERTY) + { + if (get) + { + return isTeam(); + } + else + { + setTeam(value); + return false; + } + } + if (property == ROLE_PROPERTY) + { + if (get) + { + return isRole(); + } + else + { + setRole(value); + return false; + } + } +//gbr} + // allow default implementation to flag the error + return super.internalGetSetBooleanProperty(property, get, value); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ +// {ObjectTeams: RoleTypeDeclaration can not inherit all methods, so final modifier removed + /*final*/ ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { +// ike} + if (property == JAVADOC_PROPERTY) { + if (get) { + return getJavadoc(); + } else { + setJavadoc((Javadoc) child); + return null; + } + } + if (property == NAME_PROPERTY) { + if (get) { + return getName(); + } else { + setName((SimpleName) child); + return null; + } + } + if (property == SUPERCLASS_PROPERTY) { + if (get) { + return getSuperclass(); + } else { + setSuperclass((Name) child); + return null; + } + } + if (property == SUPERCLASS_TYPE_PROPERTY) { + if (get) { + return getSuperclassType(); + } else { + setSuperclassType((Type) child); + return null; + } + } +//{ObjectTeams: + if (property == internalGuardPredicateProperty()) + { + if (get) { + return getGuardPredicate(); + } else { + setGuardPredicate((GuardPredicateDeclaration) child); + return null; + } + } +// SH} + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ +// {ObjectTeams: RoleTypeDeclaration can not inherit all methods, so final modifier removed + /*final*/ List internalGetChildListProperty(ChildListPropertyDescriptor property) +// ike} + { + if (property == MODIFIERS2_PROPERTY) { + return modifiers(); + } + if (property == TYPE_PARAMETERS_PROPERTY) { + return typeParameters(); + } + if (property == SUPER_INTERFACES_PROPERTY) { + return superInterfaces(); + } + if (property == SUPER_INTERFACE_TYPES_PROPERTY) { + return superInterfaceTypes(); + } + if (property == BODY_DECLARATIONS_PROPERTY) { + return bodyDeclarations(); + } +//{ObjectTeams: precedence: + if (property == internalPrecedenceProperty()) { + return precedences(); + } +// SH} + // allow default implementation to flag the error + return super.internalGetChildListProperty(property); + } + + /* (omit javadoc for this method) + * Method declared on BodyDeclaration. + */ +//{ObjectTeams: RoleTypeDeclaration can not inherit all methods, so final modifier removed + /*final*/ ChildPropertyDescriptor internalJavadocProperty() + { +//ike} + return JAVADOC_PROPERTY; + } + + /* (omit javadoc for this method) + * Method declared on BodyDeclaration. + */ +//{ObjectTeams: RoleTypeDeclaration can not inherit all methods, so final modifier removed + /*final*/ ChildListPropertyDescriptor internalModifiers2Property() + { +//ike} + return MODIFIERS2_PROPERTY; + } + + /* (omit javadoc for this method) + * Method declared on BodyDeclaration. + */ +//{ObjectTeams: RoleTypeDeclaration can not inherit all methods, so final modifier removed + /*final*/ SimplePropertyDescriptor internalModifiersProperty() + { +//ike} + return MODIFIERS_PROPERTY; + } + + /* (omit javadoc for this method) + * Method declared on AbstractTypeDeclaration. + */ +//{ObjectTeams: RoleTypeDeclaration can not inherit all methods, so final modifier removed + /*final*/ ChildPropertyDescriptor internalNameProperty() + { +//ike} + return NAME_PROPERTY; + } + +//{ObjectTeams: new elements + ChildPropertyDescriptor internalGuardPredicateProperty() { + return GUARD_PROPERTY; + } + ChildListPropertyDescriptor internalPrecedenceProperty() { + return PRECEDENCE_PROPERTY; + } +// SH} + + /* (omit javadoc for this method) + * Method declared on AbstractTypeDeclaration. + */ +//{ObjectTeams: RoleTypeDeclaration can not inherit all methods, so final modifier removed + /*final*/ ChildListPropertyDescriptor internalBodyDeclarationsProperty() + { +//ike} + return BODY_DECLARATIONS_PROPERTY; + } + + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ +//{ObjectTeams: RoleTypeDeclaration can not inherit all methods, so final modifier removed + /*final*/ int getNodeType0() + { +//ike} + return TYPE_DECLARATION; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + @SuppressWarnings("unchecked") + ASTNode clone0(AST target) { + TypeDeclaration result = new TypeDeclaration(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setJavadoc( + (Javadoc) ASTNode.copySubtree(target, getJavadoc())); + if (this.ast.apiLevel == AST.JLS2_INTERNAL) { + result.internalSetModifiers(getModifiers()); + result.setSuperclass( + (Name) ASTNode.copySubtree(target, getSuperclass())); + result.superInterfaces().addAll( + ASTNode.copySubtrees(target, superInterfaces())); + } + result.setInterface(isInterface()); +//{ObjectTeams: set OT-specific features (team, role) if true + result.setTeam(isTeam()); + result.setRole(isRole()); + result.precedences().addAll(ASTNode.copySubtrees(target, precedences())); + result.setGuardPredicate((GuardPredicateDeclaration)ASTNode.copySubtree(target, getGuardPredicate())); +//gbr} + result.setName((SimpleName) getName().clone(target)); + if (this.ast.apiLevel >= AST.JLS3) { + result.modifiers().addAll(ASTNode.copySubtrees(target, modifiers())); + result.typeParameters().addAll( + ASTNode.copySubtrees(target, typeParameters())); + result.setSuperclassType( + (Type) ASTNode.copySubtree(target, getSuperclassType())); + result.superInterfaceTypes().addAll( + ASTNode.copySubtrees(target, superInterfaceTypes())); + } + result.bodyDeclarations().addAll( + ASTNode.copySubtrees(target, bodyDeclarations())); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ +// {ObjectTeams: RoleTypeDeclaration can not inherit all methods, so final modifier removed + /*final*/ boolean subtreeMatch0(ASTMatcher matcher, Object other) { +//ike} + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + if (this.ast.apiLevel == AST.JLS2_INTERNAL) { + acceptChild(visitor, getJavadoc()); + acceptChild(visitor, getName()); + acceptChild(visitor, getSuperclass()); + acceptChildren(visitor, this.superInterfaceNames); + acceptChildren(visitor, this.bodyDeclarations); + } + if (this.ast.apiLevel >= AST.JLS3) { + acceptChild(visitor, getJavadoc()); + acceptChildren(visitor, this.modifiers); + acceptChild(visitor, getName()); + acceptChildren(visitor, this.typeParameters); + acceptChild(visitor, getSuperclassType()); + acceptChildren(visitor, this.superInterfaceTypes); + acceptChildren(visitor, this.bodyDeclarations); +//{ObjectTeams: + acceptChild(visitor, this.getGuardPredicate()); + acceptChildren(visitor, this._precedences); +// SH} + } + } + visitor.endVisit(this); + } + +//{ObjectTeams: convenience methods for dealing with OT-specific types, i.e. teams/roles + /** + * Returns whether this type declaration declares a team class or a class. + * + * @return <code>true</code> if this is a team class declaration, + * and <code>false</code> if this is a class declaration + */ + @Override + public boolean isTeam() + { + return _isTeam; + } + + /** + * Sets wether this type declaration declares a team class or a class. + * + * @param isTeam <code>true</code> if this is a team class + * declaration, and <code>false</code> if this is a class declaration + */ + public void setTeam(boolean isTeam) + { + preValueChange(TEAM_PROPERTY); + _isTeam = isTeam; + postValueChange(TEAM_PROPERTY); + } + + /** + * Returns whether this type declaration declares a role class or a class. + * + * @return <code>true</code> if this is a role class declaration, + * and <code>false</code> if this is a class declaration + */ + @Override + public boolean isRole() + { + return _isRole; + } + + /** + * Sets whether this type declaration declares a role class or a class. + * + * @param isRole <code>true</code> if this is a role class + * declaration, and <code>false</code> if this is a class declaration + */ + public void setRole(boolean isRole) + { + preValueChange(ROLE_PROPERTY); + _isRole = isRole; + postValueChange(ROLE_PROPERTY); + } + + public List precedences() { + return _precedences; + } +//gbr} + + /** + * Returns whether this type declaration declares a class or an + * interface. + * + * @return <code>true</code> if this is an interface declaration, + * and <code>false</code> if this is a class declaration + */ + public boolean isInterface() { + return this.isInterface; + } + + /** + * Sets whether this type declaration declares a class or an + * interface. + * + * @param isInterface <code>true</code> if this is an interface + * declaration, and <code>false</code> if this is a class + * declaration + */ + public void setInterface(boolean isInterface) { + preValueChange(INTERFACE_PROPERTY); + this.isInterface = isInterface; + postValueChange(INTERFACE_PROPERTY); + } + + /** + * Returns the live ordered list of type parameters of this type + * declaration (added in JLS3 API). This list is non-empty for parameterized types. + * + * @return the live list of type parameters + * (element type: <code>TypeParameter</code>) + * @exception UnsupportedOperationException if this operation is used in + * a JLS2 AST + * @since 3.1 + */ + public List typeParameters() { + // more efficient than just calling unsupportedIn2() to check + if (this.typeParameters == null) { + unsupportedIn2(); + } + return this.typeParameters; + } + + /** + * Returns the name of the superclass declared in this type + * declaration, or <code>null</code> if there is none (JLS2 API only). + * <p> + * Note that this child is not relevant for interface + * declarations (although it does still figure in subtree + * equality comparisons). + * </p> + * + * @return the superclass name node, or <code>null</code> if + * there is none + * @exception UnsupportedOperationException if this operation is used in + * an AST later than JLS2 + * @deprecated In the JLS3 API, this method is replaced by + * {@link #getSuperclassType()}, which returns a <code>Type</code> + * instead of a <code>Name</code>. + */ + public Name getSuperclass() { + return internalGetSuperclass(); + } + + /** + * Internal synonym for deprecated method. Used to avoid + * deprecation warnings. + * @since 3.1 + */ + /*package*/ final Name internalGetSuperclass() { + supportedOnlyIn2(); + return this.optionalSuperclassName; + } + + /** + * Returns the superclass declared in this type + * declaration, or <code>null</code> if there is none (added in JLS3 API). + * <p> + * Note that this child is not relevant for interface + * declarations (although it does still figure in subtree + * equality comparisons). + * </p> + * + * @return the superclass type node, or <code>null</code> if + * there is none + * @exception UnsupportedOperationException if this operation is used in + * a JLS2 AST + * @since 3.1 + */ + public Type getSuperclassType() { + unsupportedIn2(); + return this.optionalSuperclassType; + } + + /** + * Sets or clears the name of the superclass declared in this type + * declaration (JLS2 API only). + * <p> + * Note that this child is not relevant for interface + * declarations (although it does still figure in subtree + * equality comparisons). + * </p> + * + * @param superclassName the superclass name node, or <code>null</code> if + * there is none + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + * @exception UnsupportedOperationException if this operation is used in + * an AST later than JLS2 + * @deprecated In the JLS3 API, this method is replaced by + * {@link #setSuperclassType(Type)}, which expects a + * <code>Type</code> instead of a <code>Name</code>. + */ + public void setSuperclass(Name superclassName) { + internalSetSuperclass(superclassName); + } + + /** + * Internal synonym for deprecated method. Used to avoid + * deprecation warnings. + * @since 3.1 + */ + /*package*/ final void internalSetSuperclass(Name superclassName) { + supportedOnlyIn2(); + ASTNode oldChild = this.optionalSuperclassName; + preReplaceChild(oldChild, superclassName, SUPERCLASS_PROPERTY); + this.optionalSuperclassName = superclassName; + postReplaceChild(oldChild, superclassName, SUPERCLASS_PROPERTY); + } + + /** + * Sets or clears the superclass declared in this type + * declaration (added in JLS3 API). + * <p> + * Note that this child is not relevant for interface declarations + * (although it does still figure in subtree equality comparisons). + * </p> + * + * @param superclassType the superclass type node, or <code>null</code> if + * there is none + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + * @exception UnsupportedOperationException if this operation is used in + * a JLS2 AST + * @since 3.1 + */ + public void setSuperclassType(Type superclassType) { + unsupportedIn2(); + ASTNode oldChild = this.optionalSuperclassType; + preReplaceChild(oldChild, superclassType, SUPERCLASS_TYPE_PROPERTY); + this.optionalSuperclassType = superclassType; + postReplaceChild(oldChild, superclassType, SUPERCLASS_TYPE_PROPERTY); + } + + /** + * Returns the live ordered list of names of superinterfaces of this type + * declaration (JLS2 API only). For a class declaration, these are the names + * of the interfaces that this class implements; for an interface + * declaration, these are the names of the interfaces that this interface + * extends. + * + * @return the live list of interface names + * (element type: <code>Name</code>) + * @exception UnsupportedOperationException if this operation is used in + * an AST later than JLS2 + * @deprecated In the JLS3 API, this method is replaced by + * {@link #superInterfaceTypes()}. + */ + public List superInterfaces() { + return internalSuperInterfaces(); + } + + /** + * Internal synonym for deprecated method. Used to avoid + * deprecation warnings. + * @since 3.1 + */ + /*package*/ final List internalSuperInterfaces() { + // more efficient than just calling supportedOnlyIn2() to check + if (this.superInterfaceNames == null) { + supportedOnlyIn2(); + } + return this.superInterfaceNames; + } + + /** + * Returns the live ordered list of superinterfaces of this type + * declaration (added in JLS3 API). For a class declaration, these are the interfaces + * that this class implements; for an interface declaration, + * these are the interfaces that this interface extends. + * + * @return the live list of interface types + * (element type: <code>Type</code>) + * @exception UnsupportedOperationException if this operation is used in + * a JLS2 AST + * @since 3.1 + */ + public List superInterfaceTypes() { + // more efficient than just calling unsupportedIn2() to check + if (this.superInterfaceTypes == null) { + unsupportedIn2(); + } + return this.superInterfaceTypes; + } + + /** + * Returns the ordered list of field declarations of this type + * declaration. For a class declaration, these are the + * field declarations; for an interface declaration, these are + * the constant declarations. + * <p> + * This convenience method returns this node's body declarations + * with non-fields filtered out. Unlike <code>bodyDeclarations</code>, + * this method does not return a live result. + * </p> + * + * @return the (possibly empty) list of field declarations + */ + public FieldDeclaration[] getFields() { + List bd = bodyDeclarations(); + int fieldCount = 0; + for (Iterator it = bd.listIterator(); it.hasNext(); ) { + if (it.next() instanceof FieldDeclaration) { + fieldCount++; + } + } + FieldDeclaration[] fields = new FieldDeclaration[fieldCount]; + int next = 0; + for (Iterator it = bd.listIterator(); it.hasNext(); ) { + Object decl = it.next(); + if (decl instanceof FieldDeclaration) { + fields[next++] = (FieldDeclaration) decl; + } + } + return fields; + } + + /** + * Returns the ordered list of method declarations of this type + * declaration. + * <p> + * This convenience method returns this node's body declarations + * with non-methods filtered out. Unlike <code>bodyDeclarations</code>, + * this method does not return a live result. + * </p> + * + * @return the (possibly empty) list of method (and constructor) + * declarations + */ + public MethodDeclaration[] getMethods() { + List bd = bodyDeclarations(); + int methodCount = 0; + for (Iterator it = bd.listIterator(); it.hasNext(); ) { + if (it.next() instanceof MethodDeclaration) { + methodCount++; + } + } + MethodDeclaration[] methods = new MethodDeclaration[methodCount]; + int next = 0; + for (Iterator it = bd.listIterator(); it.hasNext(); ) { + Object decl = it.next(); + if (decl instanceof MethodDeclaration) { + methods[next++] = (MethodDeclaration) decl; + } + } + return methods; + } + +//{ObjectTeams: method getRoles() + /** + * Returns the ordered list of role type declarations of this type + * declaration. + * <p> + * This convenience method returns this node's body declarations + * with non-roles filtered out. Unlike <code>bodyDeclarations</code>, + * this method does not return a live result. + * </p> + * + * @return the (possibly empty) list of role type declarations + */ + public RoleTypeDeclaration[] getRoles() { + List bd = bodyDeclarations(); + int roleCount = 0; + for (Iterator it = bd.listIterator(); it.hasNext(); ) { + if (it.next() instanceof RoleTypeDeclaration) { + roleCount++; + } + } + RoleTypeDeclaration[] roles = new RoleTypeDeclaration[roleCount]; + int next = 0; + for (Iterator it = bd.listIterator(); it.hasNext(); ) { + Object decl = it.next(); + if (decl instanceof RoleTypeDeclaration) { + roles[next++] = (RoleTypeDeclaration) decl; + } + } + return roles; + } + + public void setGuardPredicate(GuardPredicateDeclaration predicate) { + ASTNode oldChild = this.optionalGuardPredicate; + preReplaceChild(oldChild, predicate, internalGuardPredicateProperty()); + this.optionalGuardPredicate = predicate; + postReplaceChild(oldChild, predicate, internalGuardPredicateProperty()); + } + + public GuardPredicateDeclaration getGuardPredicate() { + return optionalGuardPredicate; + } + +//jsv} + + /** + * Returns the ordered list of member type declarations of this type + * declaration. + * <p> + * This convenience method returns this node's body declarations + * with non-types filtered out. Unlike <code>bodyDeclarations</code>, + * this method does not return a live result. + * </p> + * + * @return the (possibly empty) list of member type declarations + */ + public TypeDeclaration[] getTypes() { + List bd = bodyDeclarations(); + int typeCount = 0; + for (Iterator it = bd.listIterator(); it.hasNext(); ) { + if (it.next() instanceof TypeDeclaration) { + typeCount++; + } + } + TypeDeclaration[] memberTypes = new TypeDeclaration[typeCount]; + int next = 0; + for (Iterator it = bd.listIterator(); it.hasNext(); ) { + Object decl = it.next(); + if (decl instanceof TypeDeclaration) { + memberTypes[next++] = (TypeDeclaration) decl; + } + } + return memberTypes; + } + + /* (omit javadoc for this method) + * Method declared on AsbtractTypeDeclaration. + */ + ITypeBinding internalResolveBinding() { + return this.ast.getBindingResolver().resolveType(this); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return super.memSize() + 6 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return memSize() + + (this.optionalDocComment == null ? 0 : getJavadoc().treeSize()) + + (this.modifiers == null ? 0 : this.modifiers.listSize()) + + (this.typeName == null ? 0 : getName().treeSize()) + + (this.typeParameters == null ? 0 : this.typeParameters.listSize()) + + (this.optionalSuperclassName == null ? 0 : getSuperclass().treeSize()) + + (this.optionalSuperclassType == null ? 0 : getSuperclassType().treeSize()) + + (this.superInterfaceNames == null ? 0 : this.superInterfaceNames.listSize()) + + (this.superInterfaceTypes == null ? 0 : this.superInterfaceTypes.listSize()) +//{ObjectTeams: + + (this.optionalGuardPredicate == null ? 0 : this.optionalGuardPredicate.treeSize()) + + this._precedences.listSize() +// SH} + + this.bodyDeclarations.listSize(); + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeDeclarationStatement.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeDeclarationStatement.java new file mode 100644 index 000000000..107800c0a --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeDeclarationStatement.java @@ -0,0 +1,359 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Local type declaration statement AST node type. + * <p> + * This kind of node is used to convert a type declaration + * node into a statement node by wrapping it. + * </p> + * For JLS2: + * <pre> + * TypeDeclarationStatement: + * TypeDeclaration + * </pre> + * For JLS3, the kinds of type declarations grew to include enum declarations: + * <pre> + * TypeDeclarationStatement: + * TypeDeclaration + * EnumDeclaration + * </pre> + * Although allowed at the AST, not all arrangements of AST nodes are meaningful; + * in particular, only class and enum declarations are meaningful in the context of + * a block. + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class TypeDeclarationStatement extends Statement { + + /** + * The "typeDeclaration" structural property of this node type (JLS2 API only). + * @since 3.0 + */ + public static final ChildPropertyDescriptor TYPE_DECLARATION_PROPERTY = + new ChildPropertyDescriptor(TypeDeclarationStatement.class, "typeDeclaration", TypeDeclaration.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "declaration" structural property of this node type (added in JLS3 API). + * @since 3.1 + */ + public static final ChildPropertyDescriptor DECLARATION_PROPERTY = + new ChildPropertyDescriptor(TypeDeclarationStatement.class, "declaration", AbstractTypeDeclaration.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + * @since 3.0 + */ + private static final List PROPERTY_DESCRIPTORS_2_0; + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + * @since 3.1 + */ + private static final List PROPERTY_DESCRIPTORS_3_0; + + static { + List propertyList = new ArrayList(2); + createPropertyList(TypeDeclarationStatement.class, propertyList); + addProperty(TYPE_DECLARATION_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS_2_0 = reapPropertyList(propertyList); + + propertyList = new ArrayList(2); + createPropertyList(TypeDeclarationStatement.class, propertyList); + addProperty(DECLARATION_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS_3_0 = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + if (apiLevel == AST.JLS2_INTERNAL) { + return PROPERTY_DESCRIPTORS_2_0; + } else { + return PROPERTY_DESCRIPTORS_3_0; + } + } + + /** + * The type declaration; lazily initialized; defaults to a unspecified, + * but legal, type declaration. In JLS2, corresponds to TYPE_DECLARATION_PROPERTY. + * After JLS2, corresponds to DECLARATION_PROPERTY. + * @see #typeDeclProperty + */ + private AbstractTypeDeclaration typeDecl = null; + + /** + * The child property stored on the <code>typeDecl</code> instance variable. + * In JLS2, corresponds to TYPE_DECLARATION_PROPERTY. After JLS2, corresponds to + * DECLARATION_PROPERTY. + * + * @return the property corresponding to the <code>typeDecl</code> instance variable; + * never <code>null</code> + */ + private ChildPropertyDescriptor typeDeclProperty () { + if (getAST().apiLevel() == AST.JLS2_INTERNAL) { + return TYPE_DECLARATION_PROPERTY; + } else { + return DECLARATION_PROPERTY; + } + } + + + /** + * Creates a new unparented local type declaration statement node owned + * by the given AST. By default, the local type declaration is an + * unspecified, but legal, type declaration. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + TypeDeclarationStatement(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + * @since 3.0 + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == TYPE_DECLARATION_PROPERTY) { + if (get) { + return getTypeDeclaration(); + } else { + setTypeDeclaration((TypeDeclaration) child); + return null; + } + } + if (property == DECLARATION_PROPERTY) { + if (get) { + return getDeclaration(); + } else { + setDeclaration((AbstractTypeDeclaration) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return TYPE_DECLARATION_STATEMENT; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + TypeDeclarationStatement result = + new TypeDeclarationStatement(target); + result.setSourceRange(getStartPosition(), getLength()); + result.copyLeadingComment(this); + result.setDeclaration( + (AbstractTypeDeclaration) getDeclaration().clone(target)); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + acceptChild(visitor, getDeclaration()); + } + visitor.endVisit(this); + } + + /** + * Returns the abstract type declaration of this local type declaration + * statement (added in JLS3 API). + * + * @return the type declaration node + * @since 3.1 + */ + public AbstractTypeDeclaration getDeclaration() { + if (this.typeDecl == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.typeDecl == null) { + preLazyInit(); + this.typeDecl = new TypeDeclaration(this.ast); + postLazyInit(this.typeDecl, typeDeclProperty()); + } + } + } + return this.typeDecl; + } + + /** + * Sets the abstract type declaration of this local type declaration + * statement (added in JLS3 API). + * + * @param decl the type declaration node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + * @since 3.1 + */ + public void setDeclaration(AbstractTypeDeclaration decl) { + if (decl == null) { + throw new IllegalArgumentException(); + } + // a TypeDeclarationStatement may occur inside an + // TypeDeclaration - must check cycles + ASTNode oldChild = this.typeDecl; + ChildPropertyDescriptor typeDeclProperty = typeDeclProperty(); + preReplaceChild(oldChild, decl, typeDeclProperty); + this.typeDecl= decl; + postReplaceChild(oldChild, decl, typeDeclProperty); + } + + /** + * Returns the type declaration of this local type declaration + * statement (JLS2 API only). + * + * @return the type declaration node + * @exception UnsupportedOperationException if this operation is used in + * an AST later than JLS2 + * @deprecated In the JLS3 API, this method is replaced by + * {@link #getDeclaration()}, which returns <code>AbstractTypeDeclaration</code> + * instead of <code>TypeDeclaration</code>. + */ + public TypeDeclaration getTypeDeclaration() { + return internalGetTypeDeclaration(); + } + + /** + * Internal synonym for deprecated method. Used to avoid + * deprecation warnings. + * @since 3.1 + */ + /*package*/ final TypeDeclaration internalGetTypeDeclaration() { + supportedOnlyIn2(); + return (TypeDeclaration) getDeclaration(); + } + + /** + * Sets the type declaration of this local type declaration + * statement (JLS2 API only). + * + * @param decl the type declaration node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + * @exception UnsupportedOperationException if this operation is used in + * an AST later than JLS2 + * @deprecated In the JLS3 API, this method is replaced by + * {@link #setDeclaration(AbstractTypeDeclaration)} which takes + * <code>AbstractTypeDeclaration</code> instead of + * <code>TypeDeclaration</code>. + */ + public void setTypeDeclaration(TypeDeclaration decl) { + internalSetTypeDeclaration(decl); + } + + /** + * Internal synonym for deprecated method. Used to avoid + * deprecation warnings. + * @since 3.1 + */ + /*package*/ final void internalSetTypeDeclaration(TypeDeclaration decl) { + supportedOnlyIn2(); + // forward to non-deprecated replacement method + setDeclaration(decl); + } + + /** + * Resolves and returns the binding for the class or interface declared in + * this type declaration statement. + * <p> + * Note that bindings are generally unavailable unless requested when the + * AST is being built. + * </p> + * + * @return the binding, or <code>null</code> if the binding cannot be + * resolved + */ + public ITypeBinding resolveBinding() { + // forward request to the wrapped type declaration + AbstractTypeDeclaration d = getDeclaration(); + if (d instanceof TypeDeclaration) { + return ((TypeDeclaration) d).resolveBinding(); + } else if (d instanceof AnnotationTypeDeclaration) { + return ((AnnotationTypeDeclaration) d).resolveBinding(); + } else { + // shouldn't happen + return null; + } + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return super.memSize() + 1 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.typeDecl == null ? 0 : getDeclaration().treeSize()); + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeLiteral.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeLiteral.java new file mode 100644 index 000000000..fca75acb7 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeLiteral.java @@ -0,0 +1,199 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Type literal AST node type. + * + * <pre> + * TypeLiteral: + * ( Type | <b>void</b> ) <b>.</b> <b>class</b> + * </pre> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class TypeLiteral extends Expression { + + /** + * The "type" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor TYPE_PROPERTY = + new ChildPropertyDescriptor(TypeLiteral.class, "type", Type.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List propertyList = new ArrayList(2); + createPropertyList(TypeLiteral.class, propertyList); + addProperty(TYPE_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The type; lazily initialized; defaults to a unspecified, + * legal type. + */ + private Type type = null; + + /** + * Creates a new AST node for a type literal owned by the given + * AST. By default, the expression has an unspecified (but legal) type. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + TypeLiteral(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == TYPE_PROPERTY) { + if (get) { + return getType(); + } else { + setType((Type) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return TYPE_LITERAL; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + TypeLiteral result = new TypeLiteral(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setType((Type) getType().clone(target)); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + acceptChild(visitor, getType()); + } + visitor.endVisit(this); + } + + /** + * Returns the type in this type literal expression. + * + * @return the type + */ + public Type getType() { + if (this.type == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.type == null) { + preLazyInit(); + this.type = this.ast.newPrimitiveType(PrimitiveType.INT); + postLazyInit(this.type, TYPE_PROPERTY); + } + } + } + return this.type; + } + + /** + * Sets the type in this type literal expression to the given type. + * + * @param type the new type + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public void setType(Type type) { + if (type == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.type; + preReplaceChild(oldChild, type, TYPE_PROPERTY); + this.type = type; + postReplaceChild(oldChild, type, TYPE_PROPERTY); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + // treat Operator as free + return BASE_NODE_SIZE + 1 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.type == null ? 0 : getType().treeSize()); + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeParameter.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeParameter.java new file mode 100644 index 000000000..940302dd1 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeParameter.java @@ -0,0 +1,325 @@ +/******************************************************************************* + * Copyright (c) 2003, 2008 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: + * IBM Corporation - initial API and implementation + * Technical University Berlin - extended API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Type parameter node (added in JLS3 API). + * <pre> + * TypeParameter: + * TypeVariable [ <b>extends</b> Type { <b>&</b> Type } ] + * </pre> + * + * @since 3.1 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class TypeParameter extends ASTNode { + + /** + * The "name" structural property of this node type. + */ + public static final ChildPropertyDescriptor NAME_PROPERTY = + new ChildPropertyDescriptor(TypeParameter.class, "name", SimpleName.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "typeBounds" structural property of this node type. + */ + public static final ChildListPropertyDescriptor TYPE_BOUNDS_PROPERTY = + new ChildListPropertyDescriptor(TypeParameter.class, "typeBounds", Type.class, NO_CYCLE_RISK); //$NON-NLS-1$ + +//{ObjectTeams: distinguish value parameters and <B base R>: + public static final SimplePropertyDescriptor VALUE_PARAMETER_PROPERTY = + new SimplePropertyDescriptor(TypeParameter.class, "valueParameter", boolean.class, MANDATORY); //$NON-NLS-1$ + public static final SimplePropertyDescriptor BASE_BOUND_PROPERTY = + new SimplePropertyDescriptor(TypeParameter.class, "baseBound", boolean.class, MANDATORY); //$NON-NLS-1$ +// SH} + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List propertyList = new ArrayList(3); + createPropertyList(TypeParameter.class, propertyList); + addProperty(NAME_PROPERTY, propertyList); + addProperty(TYPE_BOUNDS_PROPERTY, propertyList); +//{ObjectTeams: value parameter: + addProperty(VALUE_PARAMETER_PROPERTY, propertyList); +// SH} + PROPERTY_DESCRIPTORS = reapPropertyList(propertyList); + } + +//{ObjectTeams: value parameter, <B base R>: + private boolean isValueParameter= false; + private boolean hasBaseBound= false; +//SH} + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The type variable node; lazily initialized; defaults to an unspecfied, + * but legal, name. + */ + private SimpleName typeVariableName = null; + + /** + * The type bounds (element type: <code>Type</code>). + * Defaults to an empty list. + */ + private ASTNode.NodeList typeBounds = + new ASTNode.NodeList(TYPE_BOUNDS_PROPERTY); + + /** + * Creates a new unparented node for a parameterized type owned by the + * given AST. By default, an unspecified, but legal, type variable name, + * and no type bounds. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + TypeParameter(AST ast) { + super(ast); + unsupportedIn2(); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == NAME_PROPERTY) { + if (get) { + return getName(); + } else { + setName((SimpleName) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + +//{ObjectTeams: value parameter? + boolean internalGetSetBooleanProperty(SimplePropertyDescriptor property, boolean get, boolean value) { + if (property == VALUE_PARAMETER_PROPERTY) { + if (get) { + return isValueParameter(); + } else { + setIsValueParameter(value); + return false; + } + } + // allow default implementation to flag the error + return super.internalGetSetBooleanProperty(property, get, value); + } +// SH} + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalGetChildListProperty(ChildListPropertyDescriptor property) { + if (property == TYPE_BOUNDS_PROPERTY) { + return typeBounds(); + } + // allow default implementation to flag the error + return super.internalGetChildListProperty(property); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return TYPE_PARAMETER; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + TypeParameter result = new TypeParameter(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setName((SimpleName) ((ASTNode) getName()).clone(target)); +//{ObjectTeams: value parameter? + result.setIsValueParameter(this.isValueParameter()); +// SH} + result.typeBounds().addAll( + ASTNode.copySubtrees(target, typeBounds())); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + acceptChild(visitor, getName()); + acceptChildren(visitor, this.typeBounds); + } + visitor.endVisit(this); + } + + /** + * Returns the name of the type variable declared in this type parameter. + * + * @return the name of the type variable + */ + public SimpleName getName() { + if (this.typeVariableName == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.typeVariableName == null) { + preLazyInit(); + this.typeVariableName = new SimpleName(this.ast); + postLazyInit(this.typeVariableName, NAME_PROPERTY); + } + } + } + return this.typeVariableName; + } + + /** + * Resolves and returns the binding for this type parameter. + * <p> + * Note that bindings are generally unavailable unless requested when the + * AST is being built. + * </p> + * + * @return the binding, or <code>null</code> if the binding cannot be + * resolved + */ + public final ITypeBinding resolveBinding() { + return this.ast.getBindingResolver().resolveTypeParameter(this); + } + + /** + * Sets the name of the type variable of this type parameter to the given + * name. + * + * @param typeName the new name of this type parameter + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public void setName(SimpleName typeName) { + if (typeName == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.typeVariableName; + preReplaceChild(oldChild, typeName, NAME_PROPERTY); + this.typeVariableName = typeName; + postReplaceChild(oldChild, typeName, NAME_PROPERTY); + } + + /** + * Returns the live ordered list of type bounds of this type parameter. + * For the type parameter to be plausible, there can be at most one + * class in the list, and it must be first, and the remaining ones must be + * interfaces; the list should not contain primitive types (but array types + * and parameterized types are allowed). + * + * @return the live list of type bounds + * (element type: <code>Type</code>) + */ + public List typeBounds() { + return this.typeBounds; + } + +//{ObjectTeams: value parameters & <B base R>: + /** + * Returns whether this type parameter is a value parameter. + */ + public boolean isValueParameter() { + return this.isValueParameter; + } + + /** + * Sets whether this type parameter is a value parameter. + */ + public void setIsValueParameter(boolean isValueParameter) { + preValueChange(VALUE_PARAMETER_PROPERTY); + this.isValueParameter= isValueParameter; + postValueChange(VALUE_PARAMETER_PROPERTY); + } + + /** + * Returns whether this type parameter has a "base" bound. + */ + public boolean hasBaseBound() { + return this.hasBaseBound; + } + + /** + * Sets whether this type parameter has a "base" bound. + */ + public void setHasBaseBound(boolean hasBaseBound) { + preValueChange(BASE_BOUND_PROPERTY); + this.hasBaseBound = hasBaseBound; + postValueChange(BASE_BOUND_PROPERTY); + } +// SH} + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + // treat Code as free + return BASE_NODE_SIZE + 2 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.typeVariableName == null ? 0 : getName().treeSize()) + + this.typeBounds.listSize(); + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/VariableBinding.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/VariableBinding.java new file mode 100644 index 000000000..510fa0e9e --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/VariableBinding.java @@ -0,0 +1,408 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + * Technical University Berlin - extended API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.core.util.IModifierConstants; +import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import org.eclipse.jdt.internal.compiler.impl.Constant; +import org.eclipse.jdt.internal.compiler.impl.ReferenceContext; +import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; +import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; +import org.eclipse.jdt.internal.compiler.lookup.TagBits; +import org.eclipse.jdt.internal.compiler.lookup.TypeIds; +import org.eclipse.jdt.internal.core.JavaElement; +import org.eclipse.jdt.internal.core.LocalVariable; +import org.eclipse.jdt.internal.core.util.Util; + +/** + * Internal implementation of variable bindings. + */ +class VariableBinding implements IVariableBinding { + + private static final int VALID_MODIFIERS = Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE | + Modifier.STATIC | Modifier.FINAL | Modifier.TRANSIENT | Modifier.VOLATILE; + + private org.eclipse.jdt.internal.compiler.lookup.VariableBinding binding; + private ITypeBinding declaringClass; + private String key; + private String name; + private BindingResolver resolver; + private ITypeBinding type; + private IAnnotationBinding[] annotations; + + VariableBinding(BindingResolver resolver, org.eclipse.jdt.internal.compiler.lookup.VariableBinding binding) { + this.resolver = resolver; + this.binding = binding; + } + + public IAnnotationBinding[] getAnnotations() { + if (this.annotations != null) { + return this.annotations; + } + org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding[] internalAnnotations = this.binding.getAnnotations(); + int length = internalAnnotations == null ? 0 : internalAnnotations.length; + if (length != 0) { + IAnnotationBinding[] tempAnnotations = new IAnnotationBinding[length]; + int convertedAnnotationCount = 0; + for (int i = 0; i < length; i++) { + org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding internalAnnotation = internalAnnotations[i]; + final IAnnotationBinding annotationInstance = this.resolver.getAnnotationInstance(internalAnnotation); + if (annotationInstance == null) { + continue; + } + tempAnnotations[convertedAnnotationCount++] = annotationInstance; + } + if (convertedAnnotationCount != length) { + if (convertedAnnotationCount == 0) { + return this.annotations = AnnotationBinding.NoAnnotations; + } + System.arraycopy(tempAnnotations, 0, (tempAnnotations = new IAnnotationBinding[convertedAnnotationCount]), 0, convertedAnnotationCount); + } + return this.annotations = tempAnnotations; + } + return this.annotations = AnnotationBinding.NoAnnotations; + } + + /* (non-Javadoc) + * @see IVariableBinding#getConstantValue() + * @since 3.0 + */ + public Object getConstantValue() { + Constant c = this.binding.constant(); + if (c == null || c == Constant.NotAConstant) return null; + switch (c.typeID()) { + case TypeIds.T_boolean: + return Boolean.valueOf(c.booleanValue()); + case TypeIds.T_byte: + return new Byte(c.byteValue()); + case TypeIds.T_char: + return new Character(c.charValue()); + case TypeIds.T_double: + return new Double(c.doubleValue()); + case TypeIds.T_float: + return new Float(c.floatValue()); + case TypeIds.T_int: + return new Integer(c.intValue()); + case TypeIds.T_long: + return new Long(c.longValue()); + case TypeIds.T_short: + return new Short(c.shortValue()); + case TypeIds.T_JavaLangString: + return c.stringValue(); + } + return null; + } + + /* + * @see IVariableBinding#getDeclaringClass() + */ + public ITypeBinding getDeclaringClass() { + if (isField()) { + if (this.declaringClass == null) { + FieldBinding fieldBinding = (FieldBinding) this.binding; + this.declaringClass = this.resolver.getTypeBinding(fieldBinding.declaringClass); + } + return this.declaringClass; + } else { + return null; + } + } + + /* + * @see IVariableBinding#getDeclaringMethod() + */ + public IMethodBinding getDeclaringMethod() { + if (!isField()) { + ASTNode node = this.resolver.findDeclaringNode(this); + while (true) { + if (node == null) break; + switch(node.getNodeType()) { + case ASTNode.INITIALIZER : + return null; + case ASTNode.METHOD_DECLARATION : + MethodDeclaration methodDeclaration = (MethodDeclaration) node; + return methodDeclaration.resolveBinding(); + default: + node = node.getParent(); + } + } + } + return null; + } +//{ObjectTeams: similar to #getDeclaringMethod() + public MethodMappingElement getDeclaringMethodSpec() { + if (!isField()) { + ASTNode node = this.resolver.findDeclaringNode(this); + while (true) { + if (node == null) break; + switch(node.getNodeType()) { + case ASTNode.METHOD_SPEC: + return (MethodSpec) node; + default: + node = node.getParent(); + } + } + } + return null; + } +// SH} + + /* + * @see IBinding#getJavaElement() + */ + public IJavaElement getJavaElement() { + JavaElement element = getUnresolvedJavaElement(); + if (element == null) + return null; + return element.resolved(this.binding); + } + + /* + * @see IBinding#getKey() + */ + public String getKey() { + if (this.key == null) { + this.key = new String(this.binding.computeUniqueKey()); + } + return this.key; + } + + /* + * @see IBinding#getKind() + */ + public int getKind() { + return IBinding.VARIABLE; + } + + /* + * @see IBinding#getModifiers() + */ + public int getModifiers() { + if (isField()) { + return ((FieldBinding) this.binding).getAccessFlags() & VALID_MODIFIERS; + } + if (this.binding.isFinal()) { + return IModifierConstants.ACC_FINAL; + } + return Modifier.NONE; + } + + /* + * @see IBinding#getName() + */ + public String getName() { + if (this.name == null) { + this.name = new String(this.binding.name); + } + return this.name; + } + + /* + * @see IVariableBinding#getType() + */ + public ITypeBinding getType() { + if (this.type == null) { + this.type = this.resolver.getTypeBinding(this.binding.type); + } + return this.type; + } + + private JavaElement getUnresolvedJavaElement() { + if (isField()) { + if (this.resolver instanceof DefaultBindingResolver) { + DefaultBindingResolver defaultBindingResolver = (DefaultBindingResolver) this.resolver; + return Util.getUnresolvedJavaElement( + (FieldBinding) this.binding, + defaultBindingResolver.workingCopyOwner, + defaultBindingResolver.getBindingsToNodesMap()); + } else { + return Util.getUnresolvedJavaElement((FieldBinding) this.binding, null, null); + } + } + // local variable + if (!(this.resolver instanceof DefaultBindingResolver)) return null; + VariableDeclaration localVar = (VariableDeclaration) ((DefaultBindingResolver) this.resolver).bindingsToAstNodes.get(this); + if (localVar == null) return null; + int nameStart; + int nameLength; + int sourceStart; + int sourceLength; + if (localVar instanceof SingleVariableDeclaration) { + sourceStart = localVar.getStartPosition(); + sourceLength = localVar.getLength(); + SimpleName simpleName = ((SingleVariableDeclaration) localVar).getName(); + nameStart = simpleName.getStartPosition(); + nameLength = simpleName.getLength(); + } else { + nameStart = localVar.getStartPosition(); + nameLength = localVar.getLength(); + ASTNode node = localVar.getParent(); + sourceStart = node.getStartPosition(); + sourceLength = node.getLength(); + } + int sourceEnd = sourceStart+sourceLength-1; + char[] typeSig = this.binding.type.genericTypeSignature(); + JavaElement parent = null; + IMethodBinding declaringMethod = getDeclaringMethod(); + if (declaringMethod == null) { + ReferenceContext referenceContext = ((LocalVariableBinding) this.binding).declaringScope.referenceContext(); + if (referenceContext instanceof TypeDeclaration){ + // Local variable is declared inside an initializer + TypeDeclaration typeDeclaration = (TypeDeclaration) referenceContext; + JavaElement typeHandle = null; + if (this.resolver instanceof DefaultBindingResolver) { + DefaultBindingResolver defaultBindingResolver = (DefaultBindingResolver) this.resolver; + typeHandle = Util.getUnresolvedJavaElement( + typeDeclaration.binding, + defaultBindingResolver.workingCopyOwner, + defaultBindingResolver.getBindingsToNodesMap()); + } else { + typeHandle = Util.getUnresolvedJavaElement(typeDeclaration.binding, null, null); + } + parent = Util.getUnresolvedJavaElement(sourceStart, sourceEnd, typeHandle); + } else { + return null; + } + } else { + parent = (JavaElement) declaringMethod.getJavaElement(); + } + if (parent == null) return null; + return new LocalVariable(parent, localVar.getName().getIdentifier(), sourceStart, sourceEnd, nameStart, nameStart+nameLength-1, new String(typeSig), ((LocalVariableBinding) this.binding).declaration.annotations); + } + + /* + * @see IVariableBinding#getVariableDeclaration() + * @since 3.1 + */ + public IVariableBinding getVariableDeclaration() { + if (isField()) { + FieldBinding fieldBinding = (FieldBinding) this.binding; + return this.resolver.getVariableBinding(fieldBinding.original()); + } + return this; + } + + /* + * @see IVariableBinding#getVariableId() + */ + public int getVariableId() { + return this.binding.id; + } + + /* + * @see IVariableBinding#isParameter() + */ + public boolean isParameter() { + return (this.binding.tagBits & TagBits.IsArgument) != 0; + } + /* + * @see IBinding#isDeprecated() + */ + public boolean isDeprecated() { + if (isField()) { + return ((FieldBinding) this.binding).isDeprecated(); + } + return false; + } + + /* + * @see IVariableBinding#isEnumConstant() + * @since 3.1 + */ + public boolean isEnumConstant() { + return (this.binding.modifiers & ClassFileConstants.AccEnum) != 0; + } + + /* + * @see IBinding#isEqualTo(Binding) + * @since 3.1 + */ + public boolean isEqualTo(IBinding other) { + if (other == this) { + // identical binding - equal (key or no key) + return true; + } + if (other == null) { + // other binding missing + return false; + } + if (!(other instanceof VariableBinding)) { + return false; + } + org.eclipse.jdt.internal.compiler.lookup.VariableBinding otherBinding = ((VariableBinding) other).binding; + if (this.binding instanceof FieldBinding) { + if (otherBinding instanceof FieldBinding) { + return BindingComparator.isEqual((FieldBinding) this.binding, (FieldBinding) otherBinding); + } else { + return false; + } + } else { + if (BindingComparator.isEqual(this.binding, otherBinding)) { + IMethodBinding declaringMethod = getDeclaringMethod(); + IMethodBinding otherDeclaringMethod = ((VariableBinding) other).getDeclaringMethod(); + if (declaringMethod == null) { + if (otherDeclaringMethod != null) { + return false; + } +//{ObjectTeams: no declaring method perhaps declared in a method spec? + MethodMappingElement otherDeclaringSpec = ((VariableBinding)other).getDeclaringMethodSpec(); + if (otherDeclaringSpec != null) { + MethodMappingElement declaringSpec = getDeclaringMethodSpec(); + if (declaringSpec == null) + return false; + return declaringSpec.equals(otherDeclaringSpec); + } +// SH} + return true; + } + return declaringMethod.isEqualTo(otherDeclaringMethod); + } + return false; + } + } + + /* + * @see IVariableBinding#isField() + */ + public boolean isField() { + return this.binding instanceof FieldBinding; + } + + /* + * @see IBinding#isSynthetic() + */ + public boolean isSynthetic() { + if (isField()) { + return ((FieldBinding) this.binding).isSynthetic(); + } + return false; + } + + /* + * (non-Javadoc) + * @see org.eclipse.jdt.core.dom.IBinding#isRecovered() + */ + public boolean isRecovered() { + return false; + } + + /* + * For debugging purpose only. + * @see java.lang.Object#toString() + */ + public String toString() { + return this.binding.toString(); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/VariableDeclaration.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/VariableDeclaration.java new file mode 100644 index 000000000..9abc14ad7 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/VariableDeclaration.java @@ -0,0 +1,196 @@ +/******************************************************************************* + * Copyright (c) 2000, 2009 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +/** + * Abstract base class of all AST node types that declare a single local + * variable. + * <p> + * <pre> + * VariableDeclaration: + * SingleVariableDeclaration + * VariableDeclarationFragment + * </pre> + * </p> + * + * @see SingleVariableDeclaration + * @see VariableDeclarationFragment + * @since 2.0 + */ +public abstract class VariableDeclaration extends ASTNode { + + /** + * Returns structural property descriptor for the "extraDimensions" property + * of this node. + * + * @return the property descriptor + * @since 3.1 + */ + abstract SimplePropertyDescriptor internalExtraDimensionsProperty(); + + /** + * Returns structural property descriptor for the "extraDimensions" property + * of this node. + * + * @return the property descriptor + * @since 3.1 + */ + public final SimplePropertyDescriptor getExtraDimensionsProperty() { + return internalExtraDimensionsProperty(); + } + + /** + * Returns structural property descriptor for the "initializer" property + * of this node. + * + * @return the property descriptor + * @since 3.1 + */ + abstract ChildPropertyDescriptor internalInitializerProperty(); + + /** + * Returns structural property descriptor for the "initializer" property + * of this node. + * + * @return the property descriptor + * @since 3.1 + */ + public final ChildPropertyDescriptor getInitializerProperty() { + return internalInitializerProperty(); + } + + /** + * Returns structural property descriptor for the "name" property + * of this node. + * + * @return the property descriptor + * @since 3.1 + */ + abstract ChildPropertyDescriptor internalNameProperty(); + + /** + * Returns structural property descriptor for the "name" property + * of this node. + * + * @return the property descriptor + * @since 3.1 + */ + public final ChildPropertyDescriptor getNameProperty() { + return internalNameProperty(); + } + + /** + * Creates a new AST node for a variable declaration owned by the given AST. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + VariableDeclaration(AST ast) { + super(ast); + } + + /** + * Returns the name of the variable declared in this variable declaration. + * + * @return the variable name node + */ + public abstract SimpleName getName(); + + /** + * Sets the name of the variable declared in this variable declaration + * to the given name. + * + * @param variableName the new variable name + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public abstract void setName(SimpleName variableName); + + /** + * Returns the number of extra array dimensions over and above the + * explicitly-specified type. + * <p> + * For example, <code>int x[][]</code> has a type of + * <code>int</code> and two extra array dimensions; + * <code>int[][] x</code> has a type of <code>int[][]</code> + * and zero extra array dimensions. The two constructs have different + * ASTs, even though there are really syntactic variants of the same + * variable declaration. + * </p> + * + * @return the number of extra array dimensions + * @since 2.1 + */ + public abstract int getExtraDimensions(); + + /** + * Sets the number of extra array dimensions over and above the + * explicitly-specified type. + * <p> + * For example, <code>int x[][]</code> has a type of + * <code>int</code> and two extra array dimensions; + * <code>int[][] x</code> has a type of <code>int[][]</code> + * and zero extra array dimensions. The two constructs have different + * ASTs, even though there are really syntactic variants of the same + * variable declaration. + * </p> + * + * @param dimensions the number of array dimensions + * @exception IllegalArgumentException if the number of dimensions is + * negative + * @since 2.1 + */ + public abstract void setExtraDimensions(int dimensions); + + /** + * Returns the initializer of this variable declaration, or + * <code>null</code> if there is none. + * + * @return the initializer expression node, or <code>null</code> if + * there is none + */ + public abstract Expression getInitializer(); + + /** + * Sets or clears the initializer of this variable declaration. + * + * @param initializer the initializer expression node, or <code>null</code> + * if there is none + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public abstract void setInitializer(Expression initializer); + + /** + * Resolves and returns the binding for the variable declared in this + * variable declaration. + * <p> + * Note that bindings are generally unavailable unless requested when the + * AST is being built. + * </p> + * + * @return the binding, or <code>null</code> if the binding cannot be + * resolved + */ + public IVariableBinding resolveBinding() { + return this.ast.getBindingResolver().resolveVariable(this); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/VariableDeclarationExpression.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/VariableDeclarationExpression.java new file mode 100644 index 000000000..e02331c43 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/VariableDeclarationExpression.java @@ -0,0 +1,435 @@ +/******************************************************************************* + * Copyright (c) 2000, 2009 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * Local variable declaration expression AST node type. + * <p> + * This kind of node collects together several variable declaration fragments + * (<code>VariableDeclarationFragment</code>) into a single expression + * (<code>Expression</code>), all sharing the same modifiers and base type. + * This type of node can be used as the initializer of a + * <code>ForStatement</code>, or wrapped in an <code>ExpressionStatement</code> + * to form the equivalent of a <code>VariableDeclarationStatement</code>. + * </p> + * For JLS2: + * <pre> + * VariableDeclarationExpression: + * { Modifier } Type VariableDeclarationFragment + * { <b>,</b> VariableDeclarationFragment } + * </pre> + * For JLS3, the modifier flags were replaced by + * a list of modifier nodes (intermixed with annotations): + * <pre> + * VariableDeclarationExpression: + * { ExtendedModifier } Type VariableDeclarationFragment + * { <b>,</b> VariableDeclarationFragment } + * </pre> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class VariableDeclarationExpression extends Expression { + + /** + * The "modifiers" structural property of this node type (JLS2 API only). + * @since 3.0 + */ + public static final SimplePropertyDescriptor MODIFIERS_PROPERTY = + new SimplePropertyDescriptor(VariableDeclarationExpression.class, "modifiers", int.class, MANDATORY); //$NON-NLS-1$ + + /** + * The "modifiers" structural property of this node type (added in JLS3 API). + * @since 3.1 + */ + public static final ChildListPropertyDescriptor MODIFIERS2_PROPERTY = + new ChildListPropertyDescriptor(VariableDeclarationExpression.class, "modifiers", IExtendedModifier.class, CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "type" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor TYPE_PROPERTY = + new ChildPropertyDescriptor(VariableDeclarationExpression.class, "type", Type.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "fragments" structural property of this node type). + * @since 3.0 + */ + public static final ChildListPropertyDescriptor FRAGMENTS_PROPERTY = + new ChildListPropertyDescriptor(VariableDeclarationExpression.class, "fragments", VariableDeclarationFragment.class, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + * @since 3.0 + */ + private static final List PROPERTY_DESCRIPTORS_2_0; + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + * @since 3.1 + */ + private static final List PROPERTY_DESCRIPTORS_3_0; + + static { + List propertyList = new ArrayList(4); + createPropertyList(VariableDeclarationExpression.class, propertyList); + addProperty(MODIFIERS_PROPERTY, propertyList); + addProperty(TYPE_PROPERTY, propertyList); + addProperty(FRAGMENTS_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS_2_0 = reapPropertyList(propertyList); + + propertyList = new ArrayList(4); + createPropertyList(VariableDeclarationExpression.class, propertyList); + addProperty(MODIFIERS2_PROPERTY, propertyList); + addProperty(TYPE_PROPERTY, propertyList); + addProperty(FRAGMENTS_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS_3_0 = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + if (apiLevel == AST.JLS2_INTERNAL) { + return PROPERTY_DESCRIPTORS_2_0; + } else { + return PROPERTY_DESCRIPTORS_3_0; + } + } + + /** + * The extended modifiers (element type: <code>IExtendedModifier</code>). + * Null in JLS2. Added in JLS3; defaults to an empty list + * (see constructor). + * @since 3.0 + */ + private ASTNode.NodeList modifiers = null; + + /** + * The modifier flags; bit-wise or of Modifier flags. + * Defaults to none. Not used in 3.0. + */ + private int modifierFlags = Modifier.NONE; + + /** + * The base type; lazily initialized; defaults to an unspecified, + * legal type. + */ + private Type baseType = null; + + /** + * The list of variable declaration fragments (element type: + * {@link VariableDeclarationFragment}). Defaults to an empty list. + */ + private ASTNode.NodeList variableDeclarationFragments = + new ASTNode.NodeList(FRAGMENTS_PROPERTY); + + /** + * Creates a new unparented local variable declaration expression node + * owned by the given AST. By default, the variable declaration has: no + * modifiers, an unspecified (but legal) type, and an empty list of variable + * declaration fragments (which is syntactically illegal). + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + VariableDeclarationExpression(AST ast) { + super(ast); + if (ast.apiLevel >= AST.JLS3) { + this.modifiers = new ASTNode.NodeList(MODIFIERS2_PROPERTY); + } + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int internalGetSetIntProperty(SimplePropertyDescriptor property, boolean get, int value) { + if (property == MODIFIERS_PROPERTY) { + if (get) { + return getModifiers(); + } else { + setModifiers(value); + return 0; + } + } + // allow default implementation to flag the error + return super.internalGetSetIntProperty(property, get, value); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == TYPE_PROPERTY) { + if (get) { + return getType(); + } else { + setType((Type) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalGetChildListProperty(ChildListPropertyDescriptor property) { + if (property == MODIFIERS2_PROPERTY) { + return modifiers(); + } + if (property == FRAGMENTS_PROPERTY) { + return fragments(); + } + // allow default implementation to flag the error + return super.internalGetChildListProperty(property); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return VARIABLE_DECLARATION_EXPRESSION; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + VariableDeclarationExpression result = + new VariableDeclarationExpression(target); + result.setSourceRange(getStartPosition(), getLength()); + if (this.ast.apiLevel == AST.JLS2_INTERNAL) { + result.setModifiers(getModifiers()); + } + if (this.ast.apiLevel >= AST.JLS3) { + result.modifiers().addAll(ASTNode.copySubtrees(target, modifiers())); + } + result.setType((Type) getType().clone(target)); + result.fragments().addAll( + ASTNode.copySubtrees(target, fragments())); + return result; + + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + if (this.ast.apiLevel >= AST.JLS3) { + acceptChildren(visitor, this.modifiers); + } + acceptChild(visitor, getType()); + acceptChildren(visitor, this.variableDeclarationFragments); + } + visitor.endVisit(this); + } + + /** + * Returns the live ordered list of modifiers and annotations + * of this declaration (added in JLS3 API). + * <p> + * Note that the final modifier is the only meaningful modifier for local + * variable declarations. + * </p> + * + * @return the live list of modifiers and annotations + * (element type: <code>IExtendedModifier</code>) + * @exception UnsupportedOperationException if this operation is used in + * a JLS2 AST + * @since 3.1 + */ + public List modifiers() { + // more efficient than just calling unsupportedIn2() to check + if (this.modifiers == null) { + unsupportedIn2(); + } + return this.modifiers; + } + + /** + * Returns the modifiers explicitly specified on this declaration. + * <p> + * In the JLS3 API, this method is a convenience method that + * computes these flags from <code>modifiers()</code>. + * </p> + * + * @return the bit-wise or of <code>Modifier</code> constants + * @see Modifier + */ + public int getModifiers() { + // more efficient than checking getAST().API_LEVEL + if (this.modifiers == null) { + // JLS2 behavior - bona fide property + return this.modifierFlags; + } else { + // JLS3 behavior - convenient method + // performance could be improved by caching computed flags + // but this would require tracking changes to this.modifiers + int computedModifierFlags = Modifier.NONE; + for (Iterator it = modifiers().iterator(); it.hasNext(); ) { + Object x = it.next(); + if (x instanceof Modifier) { + computedModifierFlags |= ((Modifier) x).getKeyword().toFlagValue(); + } + } + return computedModifierFlags; + } + } + + /** + * Sets the modifiers explicitly specified on this declaration (JLS2 API only). + * <p> + * Note that the final modifier is the only meaningful modifier for local + * variable declarations. + * </p> + * + * @param modifiers the given modifiers (bit-wise or of <code>Modifier</code> constants) + * @exception UnsupportedOperationException if this operation is used in + * an AST later than JLS2 + * @see Modifier + * @deprecated In the JLS3 API, this method is replaced by + * {@link #modifiers()} which contains a list of a <code>Modifier</code> nodes. + */ + public void setModifiers(int modifiers) { + internalSetModifiers(modifiers); + } + + /** + * Internal synonym for deprecated method. Used to avoid + * deprecation warnings. + * @since 3.1 + */ + /*package*/ final void internalSetModifiers(int pmodifiers) { + supportedOnlyIn2(); + preValueChange(MODIFIERS_PROPERTY); + this.modifierFlags = pmodifiers; + postValueChange(MODIFIERS_PROPERTY); + } + + /** + * Returns the base type declared in this variable declaration. + * <p> + * N.B. The individual child variable declaration fragments may specify + * additional array dimensions. So the type of the variable are not + * necessarily exactly this type. + * </p> + * + * @return the base type + */ + public Type getType() { + if (this.baseType == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.baseType == null) { + preLazyInit(); + this.baseType = this.ast.newPrimitiveType(PrimitiveType.INT); + postLazyInit(this.baseType, TYPE_PROPERTY); + } + } + } + return this.baseType; + } + + /** + * Sets the base type declared in this variable declaration to the given + * type. + * + * @param type the new base type + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public void setType(Type type) { + if (type == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.baseType; + preReplaceChild(oldChild, type, TYPE_PROPERTY); + this.baseType = type; + postReplaceChild(oldChild, type, TYPE_PROPERTY); + } + + /** + * Returns the live list of variable declaration fragments in this + * expression. Adding and removing nodes from this list affects this node + * dynamically. All nodes in this list must be + * <code>VariableDeclarationFragment</code>s; attempts to add any other + * type of node will trigger an exception. + * + * @return the live list of variable declaration fragments in this + * expression (element type: <code>VariableDeclarationFragment</code>) + */ + public List fragments() { + return this.variableDeclarationFragments; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + // treat Operator as free + return BASE_NODE_SIZE + 4 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.modifiers == null ? 0 : this.modifiers.listSize()) + + (this.baseType == null ? 0 : getType().treeSize()) + + this.variableDeclarationFragments.listSize(); + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/VariableDeclarationFragment.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/VariableDeclarationFragment.java new file mode 100644 index 000000000..efacf8ebc --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/VariableDeclarationFragment.java @@ -0,0 +1,334 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Variable declaration fragment AST node type, used in field declarations, + * local variable declarations, and <code>ForStatement</code> initializers. + * It contrast to <code>SingleVariableDeclaration</code>, fragments are + * missing the modifiers and the type; these are located in the fragment's + * parent node. + * + * <pre> + * VariableDeclarationFragment: + * Identifier { <b>[</b><b>]</b> } [ <b>=</b> Expression ] + * </pre> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class VariableDeclarationFragment extends VariableDeclaration { + + /** + * The "name" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor NAME_PROPERTY = + new ChildPropertyDescriptor(VariableDeclarationFragment.class, "name", SimpleName.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "extraDimensions" structural property of this node type. + * @since 3.0 + */ + public static final SimplePropertyDescriptor EXTRA_DIMENSIONS_PROPERTY = + new SimplePropertyDescriptor(VariableDeclarationFragment.class, "extraDimensions", int.class, MANDATORY); //$NON-NLS-1$ + + /** + * The "initializer" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor INITIALIZER_PROPERTY = + new ChildPropertyDescriptor(VariableDeclarationFragment.class, "initializer", Expression.class, OPTIONAL, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + * @since 3.0 + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List propertyList = new ArrayList(4); + createPropertyList(VariableDeclarationFragment.class, propertyList); + addProperty(NAME_PROPERTY, propertyList); + addProperty(EXTRA_DIMENSIONS_PROPERTY, propertyList); + addProperty(INITIALIZER_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The variable name; lazily initialized; defaults to an unspecified, + * legal Java identifier. + */ + private SimpleName variableName = null; + + /** + * The number of extra array dimensions that this variable has; + * defaults to 0. + */ + private int extraArrayDimensions = 0; + + /** + * The initializer expression, or <code>null</code> if none; + * defaults to none. + */ + private Expression optionalInitializer = null; + + /** + * Creates a new AST node for a variable declaration fragment owned by the + * given AST. By default, the variable declaration has: an unspecified + * (but legal) variable name, no initializer, and no extra array dimensions. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + VariableDeclarationFragment(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on VariableDeclaration. + * @since 3.1 + */ + final SimplePropertyDescriptor internalExtraDimensionsProperty() { + return EXTRA_DIMENSIONS_PROPERTY; + } + + /* (omit javadoc for this method) + * Method declared on VariableDeclaration. + * @since 3.1 + */ + final ChildPropertyDescriptor internalInitializerProperty() { + return INITIALIZER_PROPERTY; + } + + /* (omit javadoc for this method) + * Method declared on VariableDeclaration. + * @since 3.1 + */ + final ChildPropertyDescriptor internalNameProperty() { + return NAME_PROPERTY; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int internalGetSetIntProperty(SimplePropertyDescriptor property, boolean get, int value) { + if (property == EXTRA_DIMENSIONS_PROPERTY) { + if (get) { + return getExtraDimensions(); + } else { + setExtraDimensions(value); + return 0; + } + } + // allow default implementation to flag the error + return super.internalGetSetIntProperty(property, get, value); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == NAME_PROPERTY) { + if (get) { + return getName(); + } else { + setName((SimpleName) child); + return null; + } + } + if (property == INITIALIZER_PROPERTY) { + if (get) { + return getInitializer(); + } else { + setInitializer((Expression) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return VARIABLE_DECLARATION_FRAGMENT; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + VariableDeclarationFragment result = new VariableDeclarationFragment(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setName((SimpleName) getName().clone(target)); + result.setExtraDimensions(getExtraDimensions()); + result.setInitializer( + (Expression) ASTNode.copySubtree(target, getInitializer())); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + acceptChild(visitor, getName()); + acceptChild(visitor, getInitializer()); + } + visitor.endVisit(this); + } + + /* (omit javadoc for this method) + * Method declared on VariableDeclaration. + */ + public SimpleName getName() { + if (this.variableName == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.variableName == null) { + preLazyInit(); + this.variableName = new SimpleName(this.ast); + postLazyInit(this.variableName, NAME_PROPERTY); + } + } + } + return this.variableName; + } + + /* (omit javadoc for this method) + * Method declared on VariableDeclaration. + */ + public void setName(SimpleName variableName) { + if (variableName == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.variableName; + preReplaceChild(oldChild, variableName, NAME_PROPERTY); + this.variableName = variableName; + postReplaceChild(oldChild, variableName, NAME_PROPERTY); + } + + /** + * Returns the number of extra array dimensions this variable has over + * and above the type specified in the enclosing declaration. + * <p> + * For example, in the AST for <code>int[] i, j[], k[][]</code> the + * variable declaration fragments for the variables <code>i</code>, + * <code>j</code>, and <code>k</code>, have 0, 1, and 2 extra array + * dimensions, respectively. + * </p> + * + * @return the number of extra array dimensions this variable has over + * and above the type specified in the enclosing declaration + * @since 2.0 + */ + public int getExtraDimensions() { + return this.extraArrayDimensions; + } + + /** + * Sets the number of extra array dimensions this variable has over + * and above the type specified in the enclosing declaration. + * <p> + * For example, in the AST for <code>int[] i, j[], k[][]</code> the + * variable declaration fragments for the variables <code>i</code>, + * <code>j</code>, and <code>k</code>, have 0, 1, and 2 extra array + * dimensions, respectively. + * </p> + * + * @param dimensions the given dimensions + * @since 2.0 + */ + public void setExtraDimensions(int dimensions) { + if (dimensions < 0) { + throw new IllegalArgumentException(); + } + preValueChange(EXTRA_DIMENSIONS_PROPERTY); + this.extraArrayDimensions = dimensions; + postValueChange(EXTRA_DIMENSIONS_PROPERTY); + } + + /* (omit javadoc for this method) + * Method declared on VariableDeclaration. + */ + public Expression getInitializer() { + return this.optionalInitializer; + } + + /* (omit javadoc for this method) + * Method declared on VariableDeclaration. + */ + public void setInitializer(Expression initializer) { + ASTNode oldChild = this.optionalInitializer; + preReplaceChild(oldChild, initializer, INITIALIZER_PROPERTY); + this.optionalInitializer = initializer; + postReplaceChild(oldChild, initializer, INITIALIZER_PROPERTY); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + // treat Operator as free + return BASE_NODE_SIZE + 3 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.variableName == null ? 0 : getName().treeSize()) + + (this.optionalInitializer == null ? 0 : getInitializer().treeSize()); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/VariableDeclarationStatement.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/VariableDeclarationStatement.java new file mode 100644 index 000000000..fd7d71753 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/VariableDeclarationStatement.java @@ -0,0 +1,437 @@ +/******************************************************************************* + * Copyright (c) 2000, 2009 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * Local variable declaration statement AST node type. + * <p> + * This kind of node collects several variable declaration fragments + * (<code>VariableDeclarationFragment</code>) into a statement + * (<code>Statement</code>), all sharing the same modifiers and base type. + * </p> + * For JLS2: + * <pre> + * VariableDeclarationStatement: + * { Modifier } Type VariableDeclarationFragment + * { <b>,</b> VariableDeclarationFragment } <b>;</b> + * </pre> + * For JLS3, the modifier flags were replaced by + * a list of modifier nodes (intermixed with annotations): + * <pre> + * VariableDeclarationStatement: + * { ExtendedModifier } Type VariableDeclarationFragment + * { <b>,</b> VariableDeclarationFragment } <b>;</b> + * </pre> + * <p> + * Note: This type of node is a convenience of sorts. + * An equivalent way to represent the same statement is to use + * a <code>VariableDeclarationExpression</code> + * wrapped in an <code>ExpressionStatement</code>. + * </p> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class VariableDeclarationStatement extends Statement { + + /** + * The "modifiers" structural property of this node type (JLS2 API only). + * @since 3.0 + */ + public static final SimplePropertyDescriptor MODIFIERS_PROPERTY = + new SimplePropertyDescriptor(VariableDeclarationStatement.class, "modifiers", int.class, MANDATORY); //$NON-NLS-1$ + + /** + * The "modifiers" structural property of this node type (added in JLS3 API). + * @since 3.1 + */ + public static final ChildListPropertyDescriptor MODIFIERS2_PROPERTY = + new ChildListPropertyDescriptor(VariableDeclarationStatement.class, "modifiers", IExtendedModifier.class, CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "type" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor TYPE_PROPERTY = + new ChildPropertyDescriptor(VariableDeclarationStatement.class, "type", Type.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "fragments" structural property of this node type). + * @since 3.0 + */ + public static final ChildListPropertyDescriptor FRAGMENTS_PROPERTY = + new ChildListPropertyDescriptor(VariableDeclarationStatement.class, "fragments", VariableDeclarationFragment.class, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + * @since 3.0 + */ + private static final List PROPERTY_DESCRIPTORS_2_0; + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + * @since 3.1 + */ + private static final List PROPERTY_DESCRIPTORS_3_0; + + static { + List propertyList = new ArrayList(4); + createPropertyList(VariableDeclarationStatement.class, propertyList); + addProperty(MODIFIERS_PROPERTY, propertyList); + addProperty(TYPE_PROPERTY, propertyList); + addProperty(FRAGMENTS_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS_2_0 = reapPropertyList(propertyList); + + propertyList = new ArrayList(4); + createPropertyList(VariableDeclarationStatement.class, propertyList); + addProperty(MODIFIERS2_PROPERTY, propertyList); + addProperty(TYPE_PROPERTY, propertyList); + addProperty(FRAGMENTS_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS_3_0 = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + if (apiLevel == AST.JLS2_INTERNAL) { + return PROPERTY_DESCRIPTORS_2_0; + } else { + return PROPERTY_DESCRIPTORS_3_0; + } + } + + /** + * The extended modifiers (element type: <code>IExtendedModifier</code>). + * Null in JLS2. Added in JLS3; defaults to an empty list + * (see constructor). + * @since 3.1 + */ + private ASTNode.NodeList modifiers = null; + + /** + * The modifier flagss; bit-wise or of Modifier flags. + * Defaults to none. Not used in JLS3. + */ + private int modifierFlags = Modifier.NONE; + + /** + * The base type; lazily initialized; defaults to an unspecified, + * legal type. + */ + private Type baseType = null; + + /** + * The list of variable variable declaration fragments (element type: + * {@link VariableDeclarationFragment}). Defaults to an empty list. + */ + private ASTNode.NodeList variableDeclarationFragments = + new ASTNode.NodeList(FRAGMENTS_PROPERTY); + + /** + * Creates a new unparented local variable declaration statement node owned + * by the given AST. By default, the variable declaration has: no modifiers, + * an unspecified (but legal) type, and an empty list of variable + * declaration fragments (which is syntactically illegal). + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + VariableDeclarationStatement(AST ast) { + super(ast); + if (ast.apiLevel >= AST.JLS3) { + this.modifiers = new ASTNode.NodeList(MODIFIERS2_PROPERTY); + } + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int internalGetSetIntProperty(SimplePropertyDescriptor property, boolean get, int value) { + if (property == MODIFIERS_PROPERTY) { + if (get) { + return getModifiers(); + } else { + setModifiers(value); + return 0; + } + } + // allow default implementation to flag the error + return super.internalGetSetIntProperty(property, get, value); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == TYPE_PROPERTY) { + if (get) { + return getType(); + } else { + setType((Type) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalGetChildListProperty(ChildListPropertyDescriptor property) { + if (property == MODIFIERS2_PROPERTY) { + return modifiers(); + } + if (property == FRAGMENTS_PROPERTY) { + return fragments(); + } + // allow default implementation to flag the error + return super.internalGetChildListProperty(property); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return VARIABLE_DECLARATION_STATEMENT; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + VariableDeclarationStatement result = + new VariableDeclarationStatement(target); + result.setSourceRange(getStartPosition(), getLength()); + result.copyLeadingComment(this); + if (this.ast.apiLevel == AST.JLS2_INTERNAL) { + result.setModifiers(getModifiers()); + } + if (this.ast.apiLevel >= AST.JLS3) { + result.modifiers().addAll(ASTNode.copySubtrees(target, modifiers())); + } + result.setType((Type) getType().clone(target)); + result.fragments().addAll( + ASTNode.copySubtrees(target, fragments())); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + if (this.ast.apiLevel >= AST.JLS3) { + acceptChildren(visitor, this.modifiers); + } + acceptChild(visitor, getType()); + acceptChildren(visitor, this.variableDeclarationFragments); + } + visitor.endVisit(this); + } + + /** + * Returns the live ordered list of modifiers and annotations + * of this declaration (added in JLS3 API). + * <p> + * Note that the final modifier is the only meaningful modifier for local + * variable declarations. + * </p> + * + * @return the live list of modifiers and annotations + * (element type: <code>IExtendedModifier</code>) + * @exception UnsupportedOperationException if this operation is used in + * a JLS2 AST + * @since 3.1 + */ + public List modifiers() { + // more efficient than just calling unsupportedIn2() to check + if (this.modifiers == null) { + unsupportedIn2(); + } + return this.modifiers; + } + + /** + * Returns the modifiers explicitly specified on this declaration. + * <p> + * In the JLS3 API, this method is a convenience method that + * computes these flags from <code>modifiers()</code>. + * </p> + * + * @return the bit-wise or of <code>Modifier</code> constants + * @see Modifier + */ + public int getModifiers() { + // more efficient than checking getAST().API_LEVEL + if (this.modifiers == null) { + // JLS2 behavior - bona fide property + return this.modifierFlags; + } else { + // JLS3 behavior - convenience method + // performance could be improved by caching computed flags + // but this would require tracking changes to this.modifiers + int computedModifierFlags = Modifier.NONE; + for (Iterator it = modifiers().iterator(); it.hasNext(); ) { + Object x = it.next(); + if (x instanceof Modifier) { + computedModifierFlags |= ((Modifier) x).getKeyword().toFlagValue(); + } + } + return computedModifierFlags; + } + } + + /** + * Sets the modifiers explicitly specified on this declaration (JLS2 API only). + * <p> + * Note that the final modifier is the only meaningful modifier for local + * variable declarations. + * </p> + * + * @param modifiers the given modifiers (bit-wise or of <code>Modifier</code> constants) + * @exception UnsupportedOperationException if this operation is used in + * an AST later than JLS2 + * @see Modifier + * @deprecated In the JLS3 API, this method is replaced by + * {@link #modifiers()} which contains a list of a <code>Modifier</code> nodes. + */ + public void setModifiers(int modifiers) { + internalSetModifiers(modifiers); + } + + /** + * Internal synonym for deprecated method. Used to avoid + * deprecation warnings. + * @since 3.1 + */ + /*package*/ final void internalSetModifiers(int pmodifiers) { + supportedOnlyIn2(); + preValueChange(MODIFIERS_PROPERTY); + this.modifierFlags = pmodifiers; + postValueChange(MODIFIERS_PROPERTY); + } + + /** + * Returns the base type declared in this variable declaration statement. + * <p> + * N.B. The individual child variable declaration fragments may specify + * additional array dimensions. So the type of the variable are not + * necessarily exactly this type. + * </p> + * + * @return the base type + */ + public Type getType() { + if (this.baseType == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.baseType == null) { + preLazyInit(); + this.baseType = this.ast.newPrimitiveType(PrimitiveType.INT); + postLazyInit(this.baseType, TYPE_PROPERTY); + } + } + } + return this.baseType; + } + + /** + * Sets the base type declared in this variable declaration statement to + * the given type. + * + * @param type the new base type + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + */ + public void setType(Type type) { + if (type == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.baseType; + preReplaceChild(oldChild, type, TYPE_PROPERTY); + this.baseType = type; + postReplaceChild(oldChild, type, TYPE_PROPERTY); + } + + /** + * Returns the live list of variable declaration fragments in this statement. + * Adding and removing nodes from this list affects this node dynamically. + * All nodes in this list must be <code>VariableDeclarationFragment</code>s; + * attempts to add any other type of node will trigger an + * exception. + * + * @return the live list of variable declaration fragments in this + * statement (element type: <code>VariableDeclarationFragment</code>) + */ + public List fragments() { + return this.variableDeclarationFragments; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return super.memSize() + 4 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.modifiers == null ? 0 : this.modifiers.listSize()) + + (this.baseType == null ? 0 : getType().treeSize()) + + this.variableDeclarationFragments.listSize(); + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/WhileStatement.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/WhileStatement.java new file mode 100644 index 000000000..272937062 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/WhileStatement.java @@ -0,0 +1,276 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * While statement AST node type. + * + * <pre> + * WhileStatement: + * <b>while</b> <b>(</b> Expression <b>)</b> Statement + * </pre> + * + * @since 2.0 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class WhileStatement extends Statement { + + /** + * The "expression" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor EXPRESSION_PROPERTY = + new ChildPropertyDescriptor(WhileStatement.class, "expression", Expression.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "body" structural property of this node type. + * @since 3.0 + */ + public static final ChildPropertyDescriptor BODY_PROPERTY = + new ChildPropertyDescriptor(WhileStatement.class, "body", Statement.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List propertyList = new ArrayList(3); + createPropertyList(WhileStatement.class, propertyList); + addProperty(EXPRESSION_PROPERTY, propertyList); + addProperty(BODY_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + * @since 3.0 + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The expression; lazily initialized; defaults to an unspecified, but + * legal, expression. + */ + private Expression expression = null; + + /** + * The body statement; lazily initialized; defaults to an empty block + * statement. + */ + private Statement body = null; + + /** + * Creates a new unparented while statement node owned by the given + * AST. By default, the expresssion is unspecified, but legal, and + * the body statement is an empty block. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + WhileStatement(AST ast) { + super(ast); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == EXPRESSION_PROPERTY) { + if (get) { + return getExpression(); + } else { + setExpression((Expression) child); + return null; + } + } + if (property == BODY_PROPERTY) { + if (get) { + return getBody(); + } else { + setBody((Statement) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return WHILE_STATEMENT; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + WhileStatement result = new WhileStatement(target); + result.setSourceRange(getStartPosition(), getLength()); + result.copyLeadingComment(this); + result.setExpression((Expression) getExpression().clone(target)); + result.setBody((Statement) getBody().clone(target)); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + acceptChild(visitor, getExpression()); + acceptChild(visitor, getBody()); + } + visitor.endVisit(this); + } + + /** + * Returns the expression of this while statement. + * + * @return the expression node + */ + public Expression getExpression() { + if (this.expression == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.expression == null) { + preLazyInit(); + this.expression = new SimpleName(this.ast); + postLazyInit(this.expression, EXPRESSION_PROPERTY); + } + } + } + return this.expression; + } + + /** + * Sets the expression of this while statement. + * + * @param expression the expression node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setExpression(Expression expression) { + if (expression == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.expression; + preReplaceChild(oldChild, expression, EXPRESSION_PROPERTY); + this.expression = expression; + postReplaceChild(oldChild, expression, EXPRESSION_PROPERTY); + } + + /** + * Returns the body of this while statement. + * + * @return the body statement node + */ + public Statement getBody() { + if (this.body == null) { + // lazy init must be thread-safe for readers + synchronized (this) { + if (this.body == null) { + preLazyInit(); + this.body = new Block(this.ast); + postLazyInit(this.body, BODY_PROPERTY); + } + } + } + return this.body; + } + + /** + * Sets the body of this while statement. + * <p> + * Special note: The Java language does not allow a local variable declaration + * to appear as the body of a while statement (they may only appear within a + * block). However, the AST will allow a <code>VariableDeclarationStatement</code> + * as the body of a <code>WhileStatement</code>. To get something that will + * compile, be sure to embed the <code>VariableDeclarationStatement</code> + * inside a <code>Block</code>. + * </p> + * + * @param statement the body statement node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setBody(Statement statement) { + if (statement == null) { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.body; + preReplaceChild(oldChild, statement, BODY_PROPERTY); + this.body = statement; + postReplaceChild(oldChild, statement, BODY_PROPERTY); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return super.memSize() + 2 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.expression == null ? 0 : getExpression().treeSize()) + + (this.body == null ? 0 : getBody().treeSize()); + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/WildcardType.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/WildcardType.java new file mode 100644 index 000000000..ed415af22 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/WildcardType.java @@ -0,0 +1,279 @@ +/******************************************************************************* + * Copyright (c) 2003, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * Type node for a wildcard type (added in JLS3 API). + * <pre> + * WildcardType: + * <b>?</b> [ ( <b>extends</b> | <b>super</b>) Type ] + * </pre> + * <p> + * Not all node arrangements will represent legal Java constructs. In particular, + * it is nonsense if a wildcard type node appears anywhere other than as an + * argument of a <code>ParameterizedType</code> node. + * </p> + * + * @since 3.1 + * @noinstantiate This class is not intended to be instantiated by clients. + */ +public class WildcardType extends Type { + + /** + * The "bound" structural property of this node type. + */ + public static final ChildPropertyDescriptor BOUND_PROPERTY = + new ChildPropertyDescriptor(WildcardType.class, "bound", Type.class, OPTIONAL, CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "upperBound" structural property of this node type. + */ + public static final SimplePropertyDescriptor UPPER_BOUND_PROPERTY = + new SimplePropertyDescriptor(WildcardType.class, "upperBound", boolean.class, MANDATORY); //$NON-NLS-1$ + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + private static final List PROPERTY_DESCRIPTORS; + + static { + List propertyList = new ArrayList(3); + createPropertyList(WildcardType.class, propertyList); + addProperty(BOUND_PROPERTY, propertyList); + addProperty(UPPER_BOUND_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + */ + public static List propertyDescriptors(int apiLevel) { + return PROPERTY_DESCRIPTORS; + } + + /** + * The optional type bound node; <code>null</code> if none; + * defaults to none. + */ + private Type optionalBound = null; + + /** + * Indicates whether the wildcard bound is an upper bound + * ("extends") as opposed to a lower bound ("super"). + * Defaults to <code>true</code> initially. + */ + private boolean isUpperBound = true; + + /** + * Creates a new unparented node for a wildcard type owned by the + * given AST. By default, no upper bound. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + WildcardType(AST ast) { + super(ast); + unsupportedIn2(); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final List internalStructuralPropertiesForType(int apiLevel) { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean internalGetSetBooleanProperty(SimplePropertyDescriptor property, boolean get, boolean value) { + if (property == UPPER_BOUND_PROPERTY) { + if (get) { + return isUpperBound(); + } else { + setUpperBound(value); + return false; + } + } + // allow default implementation to flag the error + return super.internalGetSetBooleanProperty(property, get, value); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { + if (property == BOUND_PROPERTY) { + if (get) { + return getBound(); + } else { + setBound((Type) child); + return null; + } + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, get, child); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final int getNodeType0() { + return WILDCARD_TYPE; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + ASTNode clone0(AST target) { + WildcardType result = new WildcardType(target); + result.setSourceRange(getStartPosition(), getLength()); + result.setBound((Type) ASTNode.copySubtree(target, getBound()), isUpperBound()); + return result; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final boolean subtreeMatch0(ASTMatcher matcher, Object other) { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + void accept0(ASTVisitor visitor) { + boolean visitChildren = visitor.visit(this); + if (visitChildren) { + // visit children in normal left to right reading order + acceptChild(visitor, getBound()); + } + visitor.endVisit(this); + } + + /** + * Returns whether this wildcard type is an upper bound + * ("extends") as opposed to a lower bound ("super"). + * <p> + * Note that this property is irrelevant for wildcards + * that do not have a bound. + * </p> + * + * @return <code>true</code> if an upper bound, + * and <code>false</code> if a lower bound + * @see #setBound(Type) + */ + public boolean isUpperBound() { + return this.isUpperBound; + } + + /** + * Returns the bound of this wildcard type if it has one. + * If {@link #isUpperBound isUpperBound} returns true, this + * is an upper bound ("? extends B"); if it returns false, this + * is a lower bound ("? super B"). + * + * @return the bound of this wildcard type, or <code>null</code> + * if none + * @see #setBound(Type) + */ + public Type getBound() { + return this.optionalBound; + } + + /** + * Sets the bound of this wildcard type to the given type and + * marks it as an upper or a lower bound. The method is + * equivalent to calling <code>setBound(type); setUpperBound(isUpperBound)</code>. + * + * @param type the new bound of this wildcard type, or <code>null</code> + * if none + * @param isUpperBound <code>true</code> for an upper bound ("? extends B"), + * and <code>false</code> for a lower bound ("? super B") + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + * @see #getBound() + * @see #isUpperBound() + */ + public void setBound(Type type, boolean isUpperBound) { + setBound(type); + setUpperBound(isUpperBound); + } + + /** + * Sets the bound of this wildcard type to the given type. + * + * @param type the new bound of this wildcard type, or <code>null</code> + * if none + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * </ul> + * @see #getBound() + */ + public void setBound(Type type) { + ASTNode oldChild = this.optionalBound; + preReplaceChild(oldChild, type, BOUND_PROPERTY); + this.optionalBound = type; + postReplaceChild(oldChild, type, BOUND_PROPERTY); + } + + /** + * Sets whether this wildcard type is an upper bound + * ("extends") as opposed to a lower bound ("super"). + * + * @param isUpperBound <code>true</code> if an upper bound, + * and <code>false</code> if a lower bound + * @see #isUpperBound() + */ + public void setUpperBound(boolean isUpperBound) { + preValueChange(UPPER_BOUND_PROPERTY); + this.isUpperBound = isUpperBound; + postValueChange(UPPER_BOUND_PROPERTY); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int memSize() { + return BASE_NODE_SIZE + 2 * 4; + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + int treeSize() { + return + memSize() + + (this.optionalBound == null ? 0 : getBound().treeSize()); + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/WithinStatement.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/WithinStatement.java new file mode 100644 index 000000000..ebee09b14 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/WithinStatement.java @@ -0,0 +1,302 @@ +/******************************************************************************* + * Copyright (c) 2000, 2010 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 + * $Id$ + * + * Please visit http://www.eclipse.org/objectteams for updates and contact. + * + * Contributors: + * IBM Corporation - initial API and implementation + * Fraunhofer FIRST - extended API and implementation + * Technical University Berlin - extended API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.dom; + +import java.util.ArrayList; +import java.util.List; + +/** + * NEW for OTDT, built in analogy to WhileStatement. + * + * Represents a within statement (OTJLD §5.2(a)), e.g. + * <code> + * within(new MyTeam()) + * { + * foo(); + * } + * </code> + * or + * <code> + * within(myTeam) + * { + * foo(); + * } + * </code> + * + * + * Within Statements consist of a team expression and + * a body element (org.eclipse.jdtd.core.dom.Block). + * + * Within statements can be used in the following AST-nodes: + * Block + * + * @author mkr + */ +public class WithinStatement extends Statement +{ + /** + * The "team expression" structural property of this node type. + */ + public static final ChildPropertyDescriptor TEAM_EXPRESSION_PROPERTY = + new ChildPropertyDescriptor(WithinStatement.class, "team expression", Expression.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + /** + * The "body" structural property of this node type. + */ + public static final ChildPropertyDescriptor BODY_PROPERTY = + new ChildPropertyDescriptor(WithinStatement.class, "body", Statement.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$ + + + /** + * A list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}), + * or null if uninitialized. + */ + @SuppressWarnings("rawtypes") + private static final List PROPERTY_DESCRIPTORS; + + static + { + List<StructuralPropertyDescriptor> propertyList = new ArrayList<StructuralPropertyDescriptor>(3); + createPropertyList(WithinStatement.class, propertyList); + addProperty(TEAM_EXPRESSION_PROPERTY, propertyList); + addProperty(BODY_PROPERTY, propertyList); + PROPERTY_DESCRIPTORS = reapPropertyList(propertyList); + } + + /** + * Returns a list of structural property descriptors for this node type. + * Clients must not modify the result. + * + * @param apiLevel the API level; one of the + * <code>AST.JLS*</code> constants + * @return a list of property descriptors (element type: + * {@link StructuralPropertyDescriptor}) + */ + @SuppressWarnings("rawtypes") + public static List propertyDescriptors(int apiLevel) + { + return PROPERTY_DESCRIPTORS; + } + + + private Expression teamExpression = null; + + /** + * The body statement; lazily initialized; defaults to an empty block + * statement. This is an addition to the statements List. + */ + private Statement body = null; + + /** + * Creates a new withinStatement node owned by the given AST. + * By default, the withinStatement is empty. + * <p> + * N.B. This constructor is package-private. + * </p> + * + * @param ast the AST that is to own this node + */ + WithinStatement(AST ast) + { + super(ast); + } + + @SuppressWarnings("rawtypes") + List internalStructuralPropertiesForType(int apiLevel) + { + return propertyDescriptors(apiLevel); + } + + /* (omit javadoc for this method) + * Method declared on ASTNode. + */ + final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean isGet, ASTNode child) + { + if (property == BODY_PROPERTY) + { + if (isGet) + { + return getBody(); + } + else + { + setBody((Statement) child); + return null; + } + } + if (property == TEAM_EXPRESSION_PROPERTY) + { + if (isGet) + { + return getTeamExpression(); + } + else + { + setTeamExpression((Expression) child); + return null; + } + + } + // allow default implementation to flag the error + return super.internalGetSetChildProperty(property, isGet, child); + } + + int getNodeType0() + { + return WITHIN_STATEMENT; + } + + boolean subtreeMatch0(ASTMatcher matcher, Object other) + { + // dispatch to correct overloaded match method + return matcher.match(this, other); + } + + ASTNode clone0(AST target) + { + WithinStatement result = new WithinStatement(target); + result.setSourceRange(this.getStartPosition(), this.getLength()); + result.copyLeadingComment(this); + result.setTeamExpression((Expression) getTeamExpression().clone(target)); + result.setBody((Statement) getBody().clone(target)); + + return result; + } + + void accept0(ASTVisitor visitor) + { + boolean visitChildren = visitor.visit(this); + if (visitChildren) + { + acceptChild(visitor, this.teamExpression); + acceptChild(visitor, this.body); + } + visitor.endVisit(this); + } + + int memSize() + { + // 3 * 4 == Number of single properties * 4 + return super.memSize() + 3 * 4 + this.body.memSize(); + } + + int treeSize() + { + return memSize() + this.body.treeSize(); + } + + /** + * Returns the team exception of this within statement. + * @return team exception + */ + public Expression getTeamExpression() + { + if (this.teamExpression == null) + { + // lazy init must be thread-safe for readers + synchronized (this) + { + if (this.teamExpression == null) + { + preLazyInit(); + this.teamExpression = new SimpleName(this.ast); + postLazyInit(this.teamExpression, TEAM_EXPRESSION_PROPERTY); + } + } + } + return this.teamExpression; + + } + + /** + * Sets the expression of this while statement. + * + * @param expression the expression node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setTeamExpression(Expression expression) + { + if (expression == null) + { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.teamExpression; + preReplaceChild(oldChild, expression, TEAM_EXPRESSION_PROPERTY); + this.teamExpression = expression; + postReplaceChild(oldChild, expression, TEAM_EXPRESSION_PROPERTY); + } + + /** + * Returns the body of this within statement. + * + * @return the body statement node + */ + public Statement getBody() + { + if (this.body == null) + { + // lazy init must be thread-safe for readers + synchronized (this) + { + if (this.body == null) + { + preLazyInit(); + this.body = new Block(this.ast); + postLazyInit(this.body, BODY_PROPERTY); + } + } + } + return this.body; + } + + /** + * Sets the body of this within statement. + * <p> + * The Following is true for while statements (for within, too? (mkr)):<br /> + * Special note: The Java language does not allow a local variable declaration + * to appear as the body of a while statement (they may only appear within a + * block). However, the AST will allow a <code>VariableDeclarationStatement</code> + * as the body of a <code>WithinStatement</code>. To get something that will + * compile, be sure to embed the <code>VariableDeclarationStatement</code> + * inside a <code>Block</code>. + * </p> + * + * @param statement the body statement node + * @exception IllegalArgumentException if: + * <ul> + * <li>the node belongs to a different AST</li> + * <li>the node already has a parent</li> + * <li>a cycle in would be created</li> + * </ul> + */ + public void setBody(Statement statement) + { + if (statement == null) + { + throw new IllegalArgumentException(); + } + ASTNode oldChild = this.body; + preReplaceChild(oldChild, statement, BODY_PROPERTY); + this.body = statement; + postReplaceChild(oldChild, statement, BODY_PROPERTY); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/package.html b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/package.html new file mode 100644 index 000000000..f0ec90214 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/package.html @@ -0,0 +1,24 @@ +<!doctype html public "-//w3c//dtd html 4.0 transitional//en"> +<html> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <meta name="Author" content="IBM"> + <meta name="GENERATOR" content="Mozilla/4.73 [en] (Windows NT 5.0; U) [Netscape]"> + <title>Package-level Javadoc</title> +</head> +<body> +The Java DOM/AST is the set of classes that model the source code of a Java program +as a structured document. + +<h2> +Package Specification</h2> + +<p><br>This package contains the Java DOM/AST classes. An API for manipulating the +source code of a Java program as a structured document. In particular, it provides +a full abstract syntax tree for a Java compilation unit, which can be queried for +resolved type information, and modified. +The principal classes are {@link org.eclipse.jdt.core.dom.AST AST} +{@link org.eclipse.jdt.core.dom.ASTNode ASTNode}, and +{@link org.eclipse.jdt.core.dom.ASTParser ASTParser}. +</body> +</html> diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/ASTNodeCreator.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/ASTNodeCreator.java new file mode 100644 index 000000000..ae142d7bf --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/ASTNodeCreator.java @@ -0,0 +1,468 @@ +/* + * Created on 01.03.2005 + * + * TODO To change the template for this generated file go to + * Window - Preferences - Java - Code Style - Code Templates + */ +package org.eclipse.jdt.core.dom.rewrite; + +import java.util.List; + +import org.eclipse.jdt.core.dom.AST; +import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.ASTParser; +import org.eclipse.jdt.core.dom.AnonymousClassDeclaration; +import org.eclipse.jdt.core.dom.CallinMappingDeclaration; +import org.eclipse.jdt.core.dom.CalloutMappingDeclaration; +import org.eclipse.jdt.core.dom.ClassInstanceCreation; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.Expression; +import org.eclipse.jdt.core.dom.FieldAccessSpec; +import org.eclipse.jdt.core.dom.GuardPredicateDeclaration; +import org.eclipse.jdt.core.dom.ImportDeclaration; +import org.eclipse.jdt.core.dom.Javadoc; +import org.eclipse.jdt.core.dom.MethodBindingOperator; +import org.eclipse.jdt.core.dom.MethodInvocation; +import org.eclipse.jdt.core.dom.MethodMappingElement; +import org.eclipse.jdt.core.dom.MethodSpec; +import org.eclipse.jdt.core.dom.Modifier; +import org.eclipse.jdt.core.dom.Name; +import org.eclipse.jdt.core.dom.PackageDeclaration; +import org.eclipse.jdt.core.dom.ParameterMapping; +import org.eclipse.jdt.core.dom.PrimitiveType; +import org.eclipse.jdt.core.dom.SimpleName; +import org.eclipse.jdt.core.dom.SingleVariableDeclaration; +import org.eclipse.jdt.core.dom.Type; +import org.eclipse.jdt.core.dom.TypeDeclaration; +import org.eclipse.jdt.core.dom.VariableDeclaration; +import org.eclipse.jdt.core.dom.Modifier.ModifierKeyword; + +/** + * New for OTDT. + * + * @author ikeman + * + * This class provides helperMethods for the creation of DOMAST-Nodes. + * + * @version $Id: ASTNodeCreator.java 22581 2009-09-24 10:26:48Z stephan $ + */ +@SuppressWarnings("unchecked") // assigning from parameterless lists :( +public class ASTNodeCreator +{ + + public static CompilationUnit createCU(AST ast, PackageDeclaration pack, List importList, List typeList) + { + CompilationUnit newCU = ast.newCompilationUnit(); + + if (pack != null) + newCU.setPackage(pack); + + if (importList != null && importList.size()!= 0) + { + List<ImportDeclaration> cuImportList = newCU.imports(); + for (int idx = 0; idx < importList.size(); idx++) + { + ImportDeclaration tmp = (ImportDeclaration)importList.get(idx); + cuImportList.add(tmp); + } + } + + if (typeList != null && typeList.size()!= 0) + { + List<TypeDeclaration> cuTypeList = newCU.types(); + for (int idx = 0; idx < typeList.size(); idx++) + { + TypeDeclaration tmp = (TypeDeclaration)typeList.get(idx); + cuTypeList.add(tmp); + } + } + return newCU; + } + + /* km: not needed anymore? + public static TypeDeclaration createTeam(AST ast, Javadoc javadoc, int modifiers, boolean isInterface, boolean isRole, + String teamClassName, String superClassName, List superInterfaces, List bodyDeclarations) + { + TypeDeclaration newTypeDecl = ast.newTypeDeclaration(); + newTypeDecl.setName(ast.newSimpleName(teamClassName)); + newTypeDecl.setTeam(true); + if(ast.apiLevel() == AST.JLS2) + newTypeDecl.setModifiers(modifiers); + else + newTypeDecl.modifiers().addAll(ast.newModifiers(modifiers)); + + newTypeDecl.setRole(isRole); + newTypeDecl.setInterface(isInterface); + + if (javadoc != null) + newTypeDecl.setJavadoc(javadoc); + + if(ast.apiLevel() == AST.JLS2) { + if (superClassName != null) + newTypeDecl.setSuperclass(ast.newName(superClassName)); + + if (superInterfaces != null && superInterfaces.size()!= 0) + { + List superInterfacesList = newTypeDecl.superInterfaces(); + for (int idx = 0; idx < superInterfaces.size(); idx++) + { + SimpleName tmp = (SimpleName)superInterfaces.get(idx); + superInterfacesList.add(tmp); + } + } + } + else { + + } + + if (bodyDeclarations != null && bodyDeclarations.size()!= 0) + { + List bodyDeclarationList = newTypeDecl.bodyDeclarations(); + for (int idx = 0; idx < bodyDeclarations.size(); idx++) + { + Object tmp = bodyDeclarations.get(idx); + bodyDeclarationList.add(tmp); + } + } + return newTypeDecl; + } + + + public static RoleTypeDeclaration createRole(AST ast, Javadoc javadoc, int modifier, String roleName, String baseClassName, + String teamClassName, String superClassName, List superInterfaces, boolean isTeam, + List bodyDeclarations) + { + RoleTypeDeclaration role = ast.newRoleTypeDeclaration(); + + if(ast.apiLevel() == AST.JLS2) + role.setModifiers(modifier); + else + role.modifiers().addAll(ast.newModifiers(modifier)); + + role.setName(ast.newName(roleName)); + role.setTeamClass(ast.newName(teamClassName)); + role.setTeam(isTeam); + role.setRole(true); + + if (javadoc != null) + role.setJavadoc(javadoc); + + if (baseClassName != null) + role.setBaseClass(ast.newName(baseClassName)); + + if (superClassName != null) + role.setSuperclass(ast.newName(superClassName)); + + if (superInterfaces != null && superInterfaces.size()!= 0) + { + List superInterfacesList = role.superInterfaces(); + for (int idx = 0; idx < superInterfaces.size(); idx++) + { + SimpleName tmp = (SimpleName)superInterfaces.get(idx); + superInterfacesList.add(tmp); + } + } + + if (bodyDeclarations != null && bodyDeclarations.size()!= 0) + { + List bodyDeclarationList = role.bodyDeclarations(); + for (int idx = 0; idx < bodyDeclarations.size(); idx++) + { + Object tmp = bodyDeclarations.get(idx); + bodyDeclarationList.add(tmp); + } + } + return role; + } +*/ + public static CallinMappingDeclaration createCallinMappingDeclaration + (AST ast, Javadoc javadoc, int modifier, MethodSpec roleMethod, List baseMethods, List paramMappings) + { + CallinMappingDeclaration newCallinMapping = ast.newCallinMappingDeclaration(); + newCallinMapping.setCallinModifier(modifier); + + newCallinMapping.setRoleMappingElement(roleMethod); + + if (javadoc != null) + newCallinMapping.setJavadoc(javadoc); + + if (baseMethods != null && baseMethods.size()!= 0) + { + List<MethodSpec> baseMappingList = newCallinMapping.getBaseMappingElements(); + for (int idx = 0; idx < baseMethods.size(); idx++) + { + MethodSpec tmp = (MethodSpec)baseMethods.get(idx); + baseMappingList.add(tmp); + } + } + if (paramMappings != null && paramMappings.size()!= 0) + { + List<ParameterMapping> parameterMappingList = newCallinMapping.getParameterMappings(); + while(!paramMappings.isEmpty()) + { + ParameterMapping tmp = (ParameterMapping)paramMappings.remove(0); + parameterMappingList.add(tmp); + } + } + return newCallinMapping; + } + + @SuppressWarnings("deprecation") + public static CalloutMappingDeclaration createCalloutMappingDeclaration( + AST ast, + Javadoc javadoc, + int modifier, + MethodMappingElement roleMethod, + MethodMappingElement baseMethod, + int bindingModifier, + List paramMappings, + boolean calloutOverride, + boolean signatureFlag) + { + CalloutMappingDeclaration newCalloutMapping = ast.newCalloutMappingDeclaration(); + + if (javadoc != null) + newCalloutMapping.setJavadoc(javadoc); + + if(ast.apiLevel() == AST.JLS2) + newCalloutMapping.setModifiers(modifier); + else + newCalloutMapping.modifiers().addAll(ast.newModifiers(modifier)); + + + newCalloutMapping.setSignatureFlag(signatureFlag); + newCalloutMapping.setRoleMappingElement(roleMethod); + newCalloutMapping.setBaseMappingElement(baseMethod); + + ModifierKeyword keyword = null; + switch (bindingModifier) { + case Modifier.OT_SET_CALLOUT: keyword = ModifierKeyword.SET_KEYWORD; break; + case Modifier.OT_GET_CALLOUT: keyword = ModifierKeyword.GET_KEYWORD; break; + } + int calloutKind = calloutOverride ? MethodBindingOperator.KIND_CALLOUT_OVERRIDE : MethodBindingOperator.KIND_CALLOUT; + newCalloutMapping.setBindingOperator(ast.newMethodBindingOperator(keyword, calloutKind)); + + if (paramMappings != null && paramMappings.size()!= 0) + { + List<ParameterMapping> parameterMapping = newCalloutMapping.getParameterMappings(); + while(!paramMappings.isEmpty()) + { + ParameterMapping tmp = (ParameterMapping)paramMappings.remove(0); + parameterMapping.add(tmp); + } + } + return newCalloutMapping; + } + + public static FieldAccessSpec createFieldAccSpec(AST ast, boolean isSetter, String fieldName, PrimitiveType.Code simpleType, String type, boolean hasSignature) + { + FieldAccessSpec newFieldAcc = ast.newFieldAccessSpec(); + newFieldAcc.setName(ast.newSimpleName(fieldName)); + + if (simpleType!= null) + newFieldAcc.setFieldType(ast.newPrimitiveType(simpleType)); + + if (type!= null) + newFieldAcc.setFieldType(ast.newSimpleType(ast.newName(type))); + + newFieldAcc.setSignatureFlag(hasSignature); + return newFieldAcc; + } + public static FieldAccessSpec createFieldAccSpec(AST ast, String fieldName, Type type) { + FieldAccessSpec newFieldAcc= ast.newFieldAccessSpec(); + newFieldAcc.setName(ast.newSimpleName(fieldName)); + newFieldAcc.setFieldType(type); + newFieldAcc.setSignatureFlag(true); + return newFieldAcc; + } + public static MethodSpec createMethodSpec(AST ast, String methodName, String returnType, List<String> argumentNames, List<String> argumentTypes, List<Integer> dimensions, boolean signatureFlag) + { + MethodSpec methodSpec = ast.newMethodSpec(); + methodSpec.setName(ast.newSimpleName(methodName)); + methodSpec.setReturnType2(createType(ast, returnType)); + methodSpec.setSignatureFlag(signatureFlag); + + if (argumentTypes !=null && argumentTypes.size()!=0) + { + List<VariableDeclaration> methodParameters = methodSpec.parameters(); + for (int idx = 0; idx < argumentTypes.size(); idx++) + { + String argumentName = (argumentNames != null) + ? argumentNames.get(idx) + : "arg"+idx; //$NON-NLS-1$ + VariableDeclaration tmp = createArgument(ast, 0, createType(ast, argumentTypes.get(idx)), argumentName, dimensions.get(idx), null); + methodParameters.add(tmp); + } + } + return methodSpec; + } + + public static MethodSpec createMethodSpec(AST ast, String methodName, Type returnType, List parameters, boolean signatureFlag) + { + MethodSpec methodSpec = ast.newMethodSpec(); + methodSpec.setName(ast.newSimpleName(methodName)); + methodSpec.setSignatureFlag(signatureFlag); + methodSpec.setReturnType2(returnType); + + if (parameters!=null && parameters.size()!=0) + { + List<VariableDeclaration> methodParameters = methodSpec.parameters(); + for (int idx = 0; idx < parameters.size(); idx++) + { + VariableDeclaration tmp = (VariableDeclaration)parameters.get(idx); + methodParameters.add(tmp); + } + } + return methodSpec; + } + + public static GuardPredicateDeclaration createGuardPredicate(AST ast, boolean isBase, Expression expression) { + GuardPredicateDeclaration result = ast.newGuardPredicateDeclaration(); + result.setBase(isBase); + result.setExpression(expression); + return result; + } + + public static Type createType(AST ast, String typeName) + { + Type primType = getPrimitveType(ast, typeName); + if (primType != null) + return primType; + + if (typeName.endsWith("[]")) //$NON-NLS-1$ + { + String [] name = typeName.split("\\[\\]"); //$NON-NLS-1$ + if (name[0] != null) + { + Type primitiveType = getPrimitveType(ast, name[0]); + if (primitiveType!= null) + return ast.newArrayType(primitiveType); + else + { + Name nameNode = ast.newName(name[0]); + Type simpleType = ast.newSimpleType(nameNode); + return ast.newArrayType(simpleType); + } + } + } + + Name name = ast.newName(typeName); + Type simpleType = ast.newSimpleType(name); + + return simpleType; + } + + private static Type getPrimitveType(AST ast, String typeName) + { + if (typeName.equals(PrimitiveType.BOOLEAN.toString())) + return ast.newPrimitiveType(PrimitiveType.BOOLEAN); + + if (typeName.equals(PrimitiveType.BYTE.toString())) + return ast.newPrimitiveType(PrimitiveType.BYTE); + + if (typeName.equals(PrimitiveType.CHAR.toString())) + return ast.newPrimitiveType(PrimitiveType.CHAR); + + if (typeName.equals(PrimitiveType.DOUBLE.toString())) + return ast.newPrimitiveType(PrimitiveType.DOUBLE); + + if (typeName.equals(PrimitiveType.FLOAT.toString())) + return ast.newPrimitiveType(PrimitiveType.FLOAT); + + if (typeName.equals(PrimitiveType.INT.toString())) + return ast.newPrimitiveType(PrimitiveType.INT); + + if (typeName.equals(PrimitiveType.LONG.toString())) + return ast.newPrimitiveType(PrimitiveType.LONG); + + if (typeName.equals(PrimitiveType.SHORT.toString())) + return ast.newPrimitiveType(PrimitiveType.SHORT); + + if (typeName.equals(PrimitiveType.VOID.toString())) + return ast.newPrimitiveType(PrimitiveType.VOID); + + return null; + } + + @SuppressWarnings("deprecation") + public static SingleVariableDeclaration createArgument(AST ast, int modifier, Type parameterType, String parameterName, int dimension, + Expression initializer) + { + SingleVariableDeclaration methodSpecParameter = ast.newSingleVariableDeclaration(); + if(ast.apiLevel() == AST.JLS2) + methodSpecParameter.setModifiers(modifier); + else + methodSpecParameter.modifiers().addAll(ast.newModifiers(modifier)); + + methodSpecParameter.setType(parameterType); + methodSpecParameter.setName(ast.newSimpleName(parameterName)); + methodSpecParameter.setExtraDimensions(dimension); + methodSpecParameter.setInitializer(initializer); + return methodSpecParameter; + } + + public static ParameterMapping createParameterMapping(AST ast, Expression expression, SimpleName identName, + String direction, boolean resultFlag) + { + ParameterMapping newParameterMapping = ast.newParameterMapping(); + newParameterMapping.setExpression(expression); + newParameterMapping.setDirection(direction); + newParameterMapping.setIdentifier(identName); + newParameterMapping.setResultFlag(resultFlag); + return newParameterMapping; + } + + public static Expression createExpression(AST ast, String expressionName, String methodName) + { + MethodInvocation expression = ast.newMethodInvocation(); + expression.setExpression(ast.newSimpleName(expressionName)); + expression.setName(ast.newSimpleName(methodName)); + return expression; + } + + + /** + * Parses the source string of an expression and returns a dom ast expression, + * that belongs to the given ast, or <code>null</code> if something goes wrong. + */ + public static Expression createExpression(AST ast, String expr) + { + ASTParser parser = ASTParser.newParser(AST.JLS3); + parser.setKind(ASTParser.K_EXPRESSION); + parser.setSource(expr.toCharArray()); + ASTNode parsedNode = parser.createAST(null); + if (parsedNode instanceof Expression) + { + Expression exprNode = (Expression)parsedNode; + + // copy the parsed expression node to the current AST + Expression newExprNode = (Expression)ASTNode.copySubtree(ast, exprNode); + return newExprNode; + } + else + { + return null; + } + } + + public static Expression createExpression(AST ast, Expression innerExpression, String className, + List arguments, AnonymousClassDeclaration anonymousClass) + { + ClassInstanceCreation expression = ast.newClassInstanceCreation(); + expression.setType(ast.newSimpleType(ast.newName(className))); + expression.setExpression(innerExpression); + expression.setAnonymousClassDeclaration(anonymousClass); + + if (arguments!=null && arguments.size()!=0) + { + List<Expression> classArguments = expression.arguments(); + for (int idx = 0; idx < arguments.size(); idx++) + { + Expression tmp = (Expression)arguments.get(idx); + classArguments.add(tmp); + } + } + return expression; + } +} + diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/ASTRewrite.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/ASTRewrite.java new file mode 100644 index 000000000..695b0b091 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/ASTRewrite.java @@ -0,0 +1,717 @@ +/******************************************************************************* + * Copyright (c) 2004, 2009 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: + * IBM Corporation - initial API and implementation + * Technical University Berlin - extended API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.dom.rewrite; + +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.eclipse.jdt.core.IClassFile; +import org.eclipse.jdt.core.ICompilationUnit; +import org.eclipse.jdt.core.ITypeRoot; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.core.dom.AST; +import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.ASTParser; +import org.eclipse.jdt.core.dom.Block; +import org.eclipse.jdt.core.dom.ChildListPropertyDescriptor; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor; +import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; +import org.eclipse.jdt.internal.compiler.parser.RecoveryScannerData; +import org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer; +import org.eclipse.jdt.internal.core.dom.rewrite.LineInformation; +import org.eclipse.jdt.internal.core.dom.rewrite.NodeInfoStore; +import org.eclipse.jdt.internal.core.dom.rewrite.NodeRewriteEvent; +import org.eclipse.jdt.internal.core.dom.rewrite.RewriteEventStore; +import org.eclipse.jdt.internal.core.dom.rewrite.TrackedNodePosition; +import org.eclipse.jdt.internal.core.dom.rewrite.RewriteEventStore.CopySourceInfo; +import org.eclipse.jdt.internal.core.dom.rewrite.RewriteEventStore.PropertyLocation; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.TextUtilities; +import org.eclipse.text.edits.MultiTextEdit; +import org.eclipse.text.edits.TextEdit; +import org.eclipse.text.edits.TextEditGroup; + +/** + * Infrastructure for modifying code by describing changes to AST nodes. + * The AST rewriter collects descriptions of modifications to nodes and + * translates these descriptions into text edits that can then be applied to + * the original source. The key thing is that this is all done without actually + * modifying the original AST, which has the virtue of allowing one to entertain + * several alternate sets of changes on the same AST (e.g., for calculating + * quick fix proposals). The rewrite infrastructure tries to generate minimal + * text changes, preserve existing comments and indentation, and follow code + * formatter settings. If the freedom to explore multiple alternate changes is + * not required, consider using the AST's built-in rewriter + * (see {@link org.eclipse.jdt.core.dom.CompilationUnit#rewrite(IDocument, Map)}). + * <p> + * The following code snippet illustrated usage of this class: + * </p> + * <pre> + * Document document = new Document("import java.util.List;\nclass X {}\n"); + * ASTParser parser = ASTParser.newParser(AST.JLS3); + * parser.setSource(document.get().toCharArray()); + * CompilationUnit cu = (CompilationUnit) parser.createAST(null); + * AST ast = cu.getAST(); + * ImportDeclaration id = ast.newImportDeclaration(); + * id.setName(ast.newName(new String[] {"java", "util", "Set"})); + * ASTRewrite rewriter = ASTRewrite.create(ast); + * TypeDeclaration td = (TypeDeclaration) cu.types().get(0); + * ITrackedNodePosition tdLocation = rewriter.track(td); + * ListRewrite lrw = rewriter.getListRewrite(cu, CompilationUnit.IMPORTS_PROPERTY); + * lrw.insertLast(id, null); + * TextEdit edits = rewriter.rewriteAST(document, null); + * UndoEdit undo = null; + * try { + * undo = edits.apply(document); + * } catch(MalformedTreeException e) { + * e.printStackTrace(); + * } catch(BadLocationException e) { + * e.printStackTrace(); + * } + * assert "import java.util.List;\nimport java.util.Set;\nclass X {}\n".equals(document.get()); + * // tdLocation.getStartPosition() and tdLocation.getLength() + * // are new source range for "class X {}" in document.get() + * </pre> + * <p> + * This class is not intended to be subclassed. + * </p> + * @since 3.0 + * @noinstantiate This class is not intended to be instantiated by clients. + * @noextend This class is not intended to be subclassed by clients. + */ +public class ASTRewrite { + + /** root node for the rewrite: Only nodes under this root are accepted */ + private final AST ast; + + private final RewriteEventStore eventStore; + private final NodeInfoStore nodeStore; + + /** + * Target source range computer; null means uninitialized; + * lazy initialized to <code>new TargetSourceRangeComputer()</code>. + * @since 3.1 + */ + private TargetSourceRangeComputer targetSourceRangeComputer = null; + + /** + * Creates a new instance for describing manipulations of + * the given AST. + * + * @param ast the AST whose nodes will be rewritten + * @return the new rewriter instance + */ + public static ASTRewrite create(AST ast) { + return new ASTRewrite(ast); + } + + /** + * Internal constructor. Creates a new instance for the given AST. + * Clients should use {@link #create(AST)} to create instances. + * + * @param ast the AST being rewritten + */ + protected ASTRewrite(AST ast) { + this.ast= ast; + this.eventStore= new RewriteEventStore(); + this.nodeStore= new NodeInfoStore(ast); + } + + /** + * Returns the AST the rewrite was set up on. + * + * @return the AST the rewrite was set up on + */ + public final AST getAST() { + return this.ast; + } + + /** + * Internal method. Returns the internal event store. + * Clients should not use. + * @return Returns the internal event store. Clients should not use. + */ + protected final RewriteEventStore getRewriteEventStore() { + return this.eventStore; + } + + /** + * Internal method. Returns the internal node info store. + * Clients should not use. + * @return Returns the internal info store. Clients should not use. + */ + protected final NodeInfoStore getNodeStore() { + return this.nodeStore; + } + + /** + * Converts all modifications recorded by this rewriter + * into an object representing the corresponding text + * edits to the given document containing the original source + * code. The document itself is not modified. + * <p> + * For nodes in the original that are being replaced or deleted, + * this rewriter computes the adjusted source ranges + * by calling <code>getTargetSourceRangeComputer().computeSourceRange(node)</code>. + * </p> + * <p> + * Calling this methods does not discard the modifications + * on record. Subsequence modifications are added to the ones + * already on record. If this method is called again later, + * the resulting text edit object will accurately reflect + * the net cumulative affect of all those changes. + * </p> + * + * @param document original document containing source code + * @param options the table of formatter options + * (key type: <code>String</code>; value type: <code>String</code>); + * or <code>null</code> to use the standard global options + * {@link JavaCore#getOptions() JavaCore.getOptions()} + * @return text edit object describing the changes to the + * document corresponding to the changes recorded by this rewriter + * @throws IllegalArgumentException An <code>IllegalArgumentException</code> + * is thrown if the document passed does not correspond to the AST that is rewritten. + */ + public TextEdit rewriteAST(IDocument document, Map options) throws IllegalArgumentException { + if (document == null) { + throw new IllegalArgumentException(); + } + + ASTNode rootNode= getRootNode(); + if (rootNode == null) { + return new MultiTextEdit(); // no changes + } + + char[] content= document.get().toCharArray(); + LineInformation lineInfo= LineInformation.create(document); + String lineDelim= TextUtilities.getDefaultLineDelimiter(document); + + ASTNode astRoot= rootNode.getRoot(); + List commentNodes= astRoot instanceof CompilationUnit ? ((CompilationUnit) astRoot).getCommentList() : null; + Map currentOptions = options == null ? JavaCore.getOptions() : options; + return internalRewriteAST(content, lineInfo, lineDelim, commentNodes, currentOptions, rootNode, (RecoveryScannerData)((CompilationUnit) astRoot).getStatementsRecoveryData()); + } + + /** + * Converts all modifications recorded by this rewriter into an object representing the the corresponding text + * edits to the source of a {@link ITypeRoot} from which the AST was created from. + * The type root's source itself is not modified by this method call. + * <p> + * Important: This API can only be used if the modified AST has been created from a + * {@link ITypeRoot} with source. That means {@link ASTParser#setSource(ICompilationUnit)}, + * {@link ASTParser#setSource(IClassFile)} or {@link ASTParser#setSource(ITypeRoot)} + * has been used when initializing the {@link ASTParser}. A {@link IllegalArgumentException} is thrown + * otherwise. An {@link IllegalArgumentException} is also thrown when the type roots buffer does not correspond + * anymore to the AST. Use {@link #rewriteAST(IDocument, Map)} for all ASTs created from other content. + * </p> + * <p> + * For nodes in the original that are being replaced or deleted, + * this rewriter computes the adjusted source ranges + * by calling <code>getTargetSourceRangeComputer().computeSourceRange(node)</code>. + * </p> + * <p> + * Calling this methods does not discard the modifications + * on record. Subsequence modifications are added to the ones + * already on record. If this method is called again later, + * the resulting text edit object will accurately reflect + * the net cumulative affect of all those changes. + * </p> + * + * @return text edit object describing the changes to the + * document corresponding to the changes recorded by this rewriter + * @throws JavaModelException A {@link JavaModelException} is thrown when + * the underlying compilation units buffer could not be accessed. + * @throws IllegalArgumentException An {@link IllegalArgumentException} + * is thrown if the document passed does not correspond to the AST that is rewritten. + * + * @since 3.2 + */ + public TextEdit rewriteAST() throws JavaModelException, IllegalArgumentException { + ASTNode rootNode= getRootNode(); + if (rootNode == null) { + return new MultiTextEdit(); // no changes + } + + ASTNode root= rootNode.getRoot(); + if (!(root instanceof CompilationUnit)) { + throw new IllegalArgumentException("This API can only be used if the AST is created from a compilation unit or class file"); //$NON-NLS-1$ + } + CompilationUnit astRoot= (CompilationUnit) root; + ITypeRoot typeRoot = astRoot.getTypeRoot(); + if (typeRoot == null || typeRoot.getBuffer() == null) { + throw new IllegalArgumentException("This API can only be used if the AST is created from a compilation unit or class file"); //$NON-NLS-1$ + } + + char[] content= typeRoot.getBuffer().getCharacters(); + LineInformation lineInfo= LineInformation.create(astRoot); + String lineDelim= typeRoot.findRecommendedLineSeparator(); + Map options= typeRoot.getJavaProject().getOptions(true); + + return internalRewriteAST(content, lineInfo, lineDelim, astRoot.getCommentList(), options, rootNode, (RecoveryScannerData)astRoot.getStatementsRecoveryData()); + } + + private TextEdit internalRewriteAST(char[] content, LineInformation lineInfo, String lineDelim, List commentNodes, Map options, ASTNode rootNode, RecoveryScannerData recoveryScannerData) { + TextEdit result= new MultiTextEdit(); + //validateASTNotModified(rootNode); + + TargetSourceRangeComputer sourceRangeComputer= getExtendedSourceRangeComputer(); + this.eventStore.prepareMovedNodes(sourceRangeComputer); +//{ObjectTeams: OT/J source? + if (this.isOTJsource) + options.put(CompilerOptions.OPTION_AllowScopedKeywords, CompilerOptions.DISABLED); + // FIXME(SH): else set PureJava to ENABLED?? +// SH} + + ASTRewriteAnalyzer visitor= new ASTRewriteAnalyzer(content, lineInfo, lineDelim, result, this.eventStore, this.nodeStore, commentNodes, options, sourceRangeComputer, recoveryScannerData); + rootNode.accept(visitor); // throws IllegalArgumentException + + this.eventStore.revertMovedNodes(); + return result; + } + + private ASTNode getRootNode() { + ASTNode node= null; + int start= -1; + int end= -1; + + for (Iterator iter= getRewriteEventStore().getChangeRootIterator(); iter.hasNext();) { + ASTNode curr= (ASTNode) iter.next(); + if (!RewriteEventStore.isNewNode(curr)) { + int currStart= curr.getStartPosition(); + int currEnd= currStart + curr.getLength(); + if (node == null || currStart < start && currEnd > end) { + start= currStart; + end= currEnd; + node= curr; + } else if (currStart < start) { + start= currStart; + } else if (currEnd > end) { + end= currEnd; + } + } + } + if (node != null) { + int currStart= node.getStartPosition(); + int currEnd= currStart + node.getLength(); + while (start < currStart || end > currEnd) { // go up until a node covers all + node= node.getParent(); + currStart= node.getStartPosition(); + currEnd= currStart + node.getLength(); + } + ASTNode parent= node.getParent(); // go up until a parent has different range + while (parent != null && parent.getStartPosition() == node.getStartPosition() && parent.getLength() == node.getLength()) { + node= parent; + parent= node.getParent(); + } + } + return node; + } + + /* + private void validateASTNotModified(ASTNode root) throws IllegalArgumentException { + GenericVisitor isModifiedVisitor= new GenericVisitor() { + protected boolean visitNode(ASTNode node) { + if ((node.getFlags() & ASTNode.ORIGINAL) == 0) { + throw new IllegalArgumentException("The AST that is rewritten must not be modified."); //$NON-NLS-1$ + } + return true; + } + }; + root.accept(isModifiedVisitor); + } + */ + + /** + * Removes the given node from its parent in this rewriter. The AST itself + * is not actually modified in any way; rather, the rewriter just records + * a note that this node should not be there. + * + * @param node the node being removed. The node can either be an original node in the AST + * or (since 3.4) a new node already inserted or used as replacement in this AST rewriter. + * @param editGroup the edit group in which to collect the corresponding + * text edits, or <code>null</code> if ungrouped + * @throws IllegalArgumentException if the node is null, or if the node is not + * part of this rewriter's AST, or if the described modification is invalid + * (such as removing a required node) + */ + public final void remove(ASTNode node, TextEditGroup editGroup) { + if (node == null) { + throw new IllegalArgumentException(); + } + + StructuralPropertyDescriptor property; + ASTNode parent; + if (RewriteEventStore.isNewNode(node)) { // remove a new node, bug 164862 + PropertyLocation location= this.eventStore.getPropertyLocation(node, RewriteEventStore.NEW); + if (location != null) { + property= location.getProperty(); + parent= location.getParent(); + } else { + throw new IllegalArgumentException("Node is not part of the rewriter's AST"); //$NON-NLS-1$ + } + } else { + property= node.getLocationInParent(); + parent= node.getParent(); + } + + if (property.isChildListProperty()) { + getListRewrite(parent, (ChildListPropertyDescriptor) property).remove(node, editGroup); + } else { + set(parent, property, null, editGroup); + } + } + + /** + * Replaces the given node in this rewriter. The replacement node + * must either be brand new (not part of the original AST) or a placeholder + * node (for example, one created by {@link #createCopyTarget(ASTNode)} + * or {@link #createStringPlaceholder(String, int)}). The AST itself + * is not actually modified in any way; rather, the rewriter just records + * a note that this node has been replaced. + * + * @param node the node being replaced. The node can either be an original node in the AST + * or (since 3.4) a new node already inserted or used as replacement in this AST rewriter. + * @param replacement the replacement node, or <code>null</code> if no + * replacement + * @param editGroup the edit group in which to collect the corresponding + * text edits, or <code>null</code> if ungrouped + * @throws IllegalArgumentException if the node is null, or if the node is not part + * of this rewriter's AST, or if the replacement node is not a new node (or + * placeholder), or if the described modification is otherwise invalid + */ + public final void replace(ASTNode node, ASTNode replacement, TextEditGroup editGroup) { + if (node == null) { + throw new IllegalArgumentException(); + } + + StructuralPropertyDescriptor property; + ASTNode parent; + if (RewriteEventStore.isNewNode(node)) { // replace a new node, bug 164862 + PropertyLocation location= this.eventStore.getPropertyLocation(node, RewriteEventStore.NEW); + if (location != null) { + property= location.getProperty(); + parent= location.getParent(); + } else { + throw new IllegalArgumentException("Node is not part of the rewriter's AST"); //$NON-NLS-1$ + } + } else { + property= node.getLocationInParent(); + parent= node.getParent(); + } + + if (property.isChildListProperty()) { + getListRewrite(parent, (ChildListPropertyDescriptor) property).replace(node, replacement, editGroup); + } else { + set(parent, property, replacement, editGroup); + } + } + + /** + * Sets the given property of the given node. If the given property is a child + * property, the value must be a replacement node that is either be brand new + * (not part of the original AST) or a placeholder node (for example, one + * created by {@link #createCopyTarget(ASTNode)} + * or {@link #createStringPlaceholder(String, int)}); or it must be + * <code>null</code>, indicating that the child should be deleted. + * If the given property is a simple property, the value must be the new + * value (primitive types must be boxed) or <code>null</code>. + * The AST itself is not actually modified in any way; rather, the rewriter + * just records a note that this node has been changed in the specified way. + * + * @param node the node + * @param property the node's property; either a simple property or a child property + * @param value the replacement child or new value, or <code>null</code> if none + * @param editGroup the edit group in which to collect the corresponding + * text edits, or <code>null</code> if ungrouped + * @throws IllegalArgumentException if the node or property is null, or if the node + * is not part of this rewriter's AST, or if the property is not a node property, + * or if the described modification is invalid + */ + public final void set(ASTNode node, StructuralPropertyDescriptor property, Object value, TextEditGroup editGroup) { + if (node == null || property == null) { + throw new IllegalArgumentException(); + } + validateIsCorrectAST(node); + validatePropertyType(property, value); + validateIsPropertyOfNode(property, node); + + NodeRewriteEvent nodeEvent= this.eventStore.getNodeEvent(node, property, true); + nodeEvent.setNewValue(value); + if (editGroup != null) { + this.eventStore.setEventEditGroup(nodeEvent, editGroup); + } + } + + /** + * Returns the value of the given property as managed by this rewriter. If the property + * has been removed, <code>null</code> is returned. If it has been replaced, the replacing value + * is returned. If the property has not been changed yet, the original value is returned. + * <p> + * For child list properties use {@link ListRewrite#getRewrittenList()} to get access to the + * rewritten nodes in a list. </p> + * + * @param node the node + * @param property the node's property + * @return the value of the given property as managed by this rewriter + * + * @since 3.2 + */ + public Object get(ASTNode node, StructuralPropertyDescriptor property) { + if (node == null || property == null) { + throw new IllegalArgumentException(); + } + if (property.isChildListProperty()) { + throw new IllegalArgumentException("Use the list rewriter to access nodes in a list"); //$NON-NLS-1$ + } + return this.eventStore.getNewValue(node, property); + } + + /** + * Creates and returns a new rewriter for describing modifications to the + * given list property of the given node. + * + * @param node the node + * @param property the node's property; the child list property + * @return a new list rewriter object + * @throws IllegalArgumentException if the node or property is null, or if the node + * is not part of this rewriter's AST, or if the property is not a node property, + * or if the described modification is invalid + */ + public final ListRewrite getListRewrite(ASTNode node, ChildListPropertyDescriptor property) { + if (node == null || property == null) { + throw new IllegalArgumentException(); + } + + validateIsCorrectAST(node); + validateIsListProperty(property); + validateIsPropertyOfNode(property, node); + + return new ListRewrite(this, node, property); + } + + /** + * Returns an object that tracks the source range of the given node + * across the rewrite to its AST. Upon return, the result object reflects + * the given node's current source range in the AST. After + * <code>rewrite</code> is called, the result object is updated to + * reflect the given node's source range in the rewritten AST. + * + * @param node the node to track + * @return an object that tracks the source range of <code>node</code> + * @throws IllegalArgumentException if the node is null, or if the node + * is not part of this rewriter's AST, or if the node is already being + * tracked + */ + public final ITrackedNodePosition track(ASTNode node) { + if (node == null) { + throw new IllegalArgumentException(); + } + TextEditGroup group= this.eventStore.getTrackedNodeData(node); + if (group == null) { + group= new TextEditGroup("internal"); //$NON-NLS-1$ + this.eventStore.setTrackedNodeData(node, group); + } + return new TrackedNodePosition(group, node); + } + + private void validateIsExistingNode(ASTNode node) { + if (node.getStartPosition() == -1) { + throw new IllegalArgumentException("Node is not an existing node"); //$NON-NLS-1$ + } + } + + private void validateIsCorrectAST(ASTNode node) { + if (node.getAST() != getAST()) { + throw new IllegalArgumentException("Node is not inside the AST"); //$NON-NLS-1$ + } + } + + private void validateIsListProperty(StructuralPropertyDescriptor property) { + if (!property.isChildListProperty()) { + String message= property.getId() + " is not a list property"; //$NON-NLS-1$ + throw new IllegalArgumentException(message); + } + } + + private void validateIsPropertyOfNode(StructuralPropertyDescriptor property, ASTNode node) { + if (!property.getNodeClass().isInstance(node)) { + String message= property.getId() + " is not a property of type " + node.getClass().getName(); //$NON-NLS-1$ + throw new IllegalArgumentException(message); + } + } + + private void validatePropertyType(StructuralPropertyDescriptor prop, Object node) { + if (prop.isChildListProperty()) { + String message= "Can not modify a list property, use a list rewriter"; //$NON-NLS-1$ + throw new IllegalArgumentException(message); + } + } + + /** + * Creates and returns a placeholder node for a source string that is to be inserted into + * the output document at the position corresponding to the placeholder. + * The string will be inserted without being reformatted beyond correcting + * the indentation level. The placeholder node can either be inserted as new or + * used to replace an existing node. + * + * @param code the string to be inserted; lines should should not have extra indentation + * @param nodeType the ASTNode type that corresponds to the passed code. + * @return the new placeholder node + * @throws IllegalArgumentException if the code is null, or if the node + * type is invalid + */ + public final ASTNode createStringPlaceholder(String code, int nodeType) { + if (code == null) { + throw new IllegalArgumentException(); + } + ASTNode placeholder= getNodeStore().newPlaceholderNode(nodeType); + if (placeholder == null) { + throw new IllegalArgumentException("String placeholder is not supported for type" + nodeType); //$NON-NLS-1$ + } + + getNodeStore().markAsStringPlaceholder(placeholder, code); + return placeholder; + } + + /** + * Creates and returns a node that represents a sequence of nodes. + * Each of the given nodes must be either be brand new (not part of the original AST), or + * a placeholder node (for example, one created by {@link #createCopyTarget(ASTNode)} + * or {@link #createStringPlaceholder(String, int)}), or another group node. + * The type of the returned node is unspecified. The returned node can be used + * to replace an existing node (or as an element of another group node). + * When the document is rewritten, the source code for each of the given nodes is + * inserted, in order, into the output document at the position corresponding to the + * group (indentation is adjusted). + * + * @param targetNodes the nodes to go in the group + * @return the new group node + * @throws IllegalArgumentException if the targetNodes is <code>null</code> or empty + * @since 3.1 + */ + public final ASTNode createGroupNode(ASTNode[] targetNodes) { + if (targetNodes == null || targetNodes.length == 0) { + throw new IllegalArgumentException(); + } + Block res= getNodeStore().createCollapsePlaceholder(); + ListRewrite listRewrite= getListRewrite(res, Block.STATEMENTS_PROPERTY); + for (int i= 0; i < targetNodes.length; i++) { + listRewrite.insertLast(targetNodes[i], null); + } + return res; + } + + + private ASTNode createTargetNode(ASTNode node, boolean isMove) { + if (node == null) { + throw new IllegalArgumentException(); + } + validateIsExistingNode(node); + validateIsCorrectAST(node); + CopySourceInfo info= getRewriteEventStore().markAsCopySource(node.getParent(), node.getLocationInParent(), node, isMove); + + ASTNode placeholder= getNodeStore().newPlaceholderNode(node.getNodeType()); + if (placeholder == null) { + throw new IllegalArgumentException("Creating a target node is not supported for nodes of type" + node.getClass().getName()); //$NON-NLS-1$ + } + getNodeStore().markAsCopyTarget(placeholder, info); + + return placeholder; + } + + /** + * Creates and returns a placeholder node for a true copy of the given node. + * The placeholder node can either be inserted as new or used to replace an + * existing node. When the document is rewritten, a copy of the source code + * for the given node is inserted into the output document at the position + * corresponding to the placeholder (indentation is adjusted). + * + * @param node the node to create a copy placeholder for + * @return the new placeholder node + * @throws IllegalArgumentException if the node is null, or if the node + * is not part of this rewriter's AST + */ + public final ASTNode createCopyTarget(ASTNode node) { + return createTargetNode(node, false); + } + + /** + * Creates and returns a placeholder node for the new locations of the given node. + * After obtaining a placeholder, the node should then to be removed or replaced. + * The placeholder node can either be inserted as new or used to replace an + * existing node. When the document is rewritten, the source code for the given + * node is inserted into the output document at the position corresponding to the + * placeholder (indentation is adjusted). + * + * @param node the node to create a move placeholder for + * @return the new placeholder node + * @throws IllegalArgumentException if the node is null, or if the node + * is not part of this rewriter's AST + */ + public final ASTNode createMoveTarget(ASTNode node) { + return createTargetNode(node, true); + } + + /** + * Returns the extended source range computer for this AST rewriter. + * The default value is a <code>new TargetSourceRangeComputer()</code>. + * + * @return an extended source range computer + * @since 3.1 + */ + public final TargetSourceRangeComputer getExtendedSourceRangeComputer() { + if (this.targetSourceRangeComputer == null) { + // lazy initialize + this.targetSourceRangeComputer = new TargetSourceRangeComputer(); + } + return this.targetSourceRangeComputer; + } + + /** + * Sets a custom target source range computer for this AST rewriter. This is advanced feature to modify how + * comments are associated with nodes, which should be done only in special cases. + * + * @param computer a target source range computer, + * or <code>null</code> to restore the default value of + * <code>new TargetSourceRangeComputer()</code> + * @since 3.1 + */ + public final void setTargetSourceRangeComputer(TargetSourceRangeComputer computer) { + // if computer==null, rely on lazy init code in getTargetSourceRangeComputer() + this.targetSourceRangeComputer = computer; + } + + /** + * Returns a string suitable for debugging purposes (only). + * + * @return a debug string + */ + public String toString() { + StringBuffer buf= new StringBuffer(); + buf.append("Events:\n"); //$NON-NLS-1$ + // be extra careful of uninitialized or mangled instances + if (this.eventStore != null) { + buf.append(this.eventStore.toString()); + } + return buf.toString(); + } + +//{ObjectTeams: + boolean isOTJsource= false; + public void setToOTJ() { + this.isOTJsource= true; + } +// SH} +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/ITrackedNodePosition.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/ITrackedNodePosition.java new file mode 100644 index 000000000..ddd62d5a1 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/ITrackedNodePosition.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2004, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.dom.rewrite; + +/** + * A tracked node position is returned when a rewrite change is + * requested to be tracked. + * <p> + * This interface is not intended to be implemented by clients. + * </p> + * + * @see ASTRewrite#track(org.eclipse.jdt.core.dom.ASTNode) + * @since 3.0 + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface ITrackedNodePosition { + + /** + * Returns the original or modified start position of the tracked node depending if called before + * or after the rewrite is applied. <code>-1</code> is returned for removed nodes. + * + * @return the original or modified start position of the tracked node + */ + public int getStartPosition(); + + /** + * Returns the original or modified length of the tracked node depending if called before + * or after the rewrite is applied. <code>-1</code> is returned for removed nodes. + * + * @return the original or modified length of the tracked node + */ + public int getLength(); + + +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/ImportRewrite.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/ImportRewrite.java new file mode 100644 index 000000000..528859529 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/ImportRewrite.java @@ -0,0 +1,1227 @@ +/******************************************************************************* + * Copyright (c) 2000, 2010 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: + * IBM Corporation - initial API and implementation + * Technical University Berlin - extended API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.core.dom.rewrite; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.SubProgressMonitor; +import org.eclipse.jdt.core.Flags; +import org.eclipse.jdt.core.ICompilationUnit; +import org.eclipse.jdt.core.IImportDeclaration; +import org.eclipse.jdt.core.ITypeRoot; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.core.Signature; +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.core.dom.*; +import org.eclipse.jdt.internal.core.dom.rewrite.ImportRewriteAnalyzer; +import org.eclipse.jdt.internal.core.util.Messages; +import org.eclipse.text.edits.MultiTextEdit; +import org.eclipse.text.edits.TextEdit; + + +/** + * The {@link ImportRewrite} helps updating imports following a import order and on-demand imports threshold as configured by a project. + * <p> + * The import rewrite is created on a compilation unit and collects references to types that are added or removed. When adding imports, e.g. using + * {@link #addImport(String)}, the import rewrite evaluates if the type can be imported and returns the a reference to the type that can be used in code. + * This reference is either unqualified if the import could be added, or fully qualified if the import failed due to a conflict with another element of the same name. + * </p> + * <p> + * On {@link #rewriteImports(IProgressMonitor)} the rewrite translates these descriptions into + * text edits that can then be applied to the original source. The rewrite infrastructure tries to generate minimal text changes and only + * works on the import statements. It is possible to combine the result of an import rewrite with the result of a {@link org.eclipse.jdt.core.dom.rewrite.ASTRewrite} + * as long as no import statements are modified by the AST rewrite. + * </p> + * <p>The options controlling the import order and on-demand thresholds are: + * <ul><li>{@link #setImportOrder(String[])} specifies the import groups and their preferred order</li> + * <li>{@link #setOnDemandImportThreshold(int)} specifies the number of imports in a group needed for a on-demand import statement (star import)</li> + * <li>{@link #setStaticOnDemandImportThreshold(int)} specifies the number of static imports in a group needed for a on-demand import statement (star import)</li> + *</ul> + * This class is not intended to be subclassed. + * </p> + * @since 3.2 + */ +@SuppressWarnings("unchecked") +public final class ImportRewrite { + + /** + * A {@link ImportRewrite.ImportRewriteContext} can optionally be used in e.g. {@link ImportRewrite#addImport(String, ImportRewrite.ImportRewriteContext)} to + * give more information about the types visible in the scope. These types can be for example inherited inner types where it is + * unnecessary to add import statements for. + * + * </p> + * <p> + * This class can be implemented by clients. + * </p> + */ + public static abstract class ImportRewriteContext { + + /** + * Result constant signaling that the given element is know in the context. + */ + public final static int RES_NAME_FOUND= 1; + + /** + * Result constant signaling that the given element is not know in the context. + */ + public final static int RES_NAME_UNKNOWN= 2; + + /** + * Result constant signaling that the given element is conflicting with an other element in the context. + */ + public final static int RES_NAME_CONFLICT= 3; + + /** + * Kind constant specifying that the element is a type import. + */ + public final static int KIND_TYPE= 1; + + /** + * Kind constant specifying that the element is a static field import. + */ + public final static int KIND_STATIC_FIELD= 2; + + /** + * Kind constant specifying that the element is a static method import. + */ + public final static int KIND_STATIC_METHOD= 3; + + /** + * Searches for the given element in the context and reports if the element is known ({@link #RES_NAME_FOUND}), + * unknown ({@link #RES_NAME_UNKNOWN}) or if its name conflicts ({@link #RES_NAME_CONFLICT}) with an other element. + * @param qualifier The qualifier of the element, can be package or the qualified name of a type + * @param name The simple name of the element; either a type, method or field name or * for on-demand imports. + * @param kind The kind of the element. Can be either {@link #KIND_TYPE}, {@link #KIND_STATIC_FIELD} or + * {@link #KIND_STATIC_METHOD}. Implementors should be prepared for new, currently unspecified kinds and return + * {@link #RES_NAME_UNKNOWN} by default. + * @return Returns the result of the lookup. Can be either {@link #RES_NAME_FOUND}, {@link #RES_NAME_UNKNOWN} or + * {@link #RES_NAME_CONFLICT}. + */ + public abstract int findInContext(String qualifier, String name, int kind); + } + + private static final char STATIC_PREFIX= 's'; + private static final char NORMAL_PREFIX= 'n'; +//{ObjectTeams: + private static final char BASE_PREFIX= 'b'; +// SH} + + private final ImportRewriteContext defaultContext; + + private final ICompilationUnit compilationUnit; + private final CompilationUnit astRoot; + + private final boolean restoreExistingImports; + private final List existingImports; + private final Map importsKindMap; + + private String[] importOrder; + private int importOnDemandThreshold; + private int staticImportOnDemandThreshold; + + private List addedImports; + private List removedImports; + + private String[] createdImports; + private String[] createdStaticImports; + +//{ObjectTeams: import base: + private List<String> importsToMarkAsBase; +// SH} + + private boolean filterImplicitImports; + + /** + * Creates a {@link ImportRewrite} from a {@link ICompilationUnit}. If <code>restoreExistingImports</code> + * is <code>true</code>, all existing imports are kept, and new imports will be inserted at best matching locations. If + * <code>restoreExistingImports</code> is <code>false</code>, the existing imports will be removed and only the + * newly added imports will be created. + * <p> + * Note that {@link #create(ICompilationUnit, boolean)} is more efficient than this method if an AST for + * the compilation unit is already available. + * </p> + * @param cu the compilation unit to create the imports for + * @param restoreExistingImports specifies if the existing imports should be kept or removed. + * @return the created import rewriter. + * @throws JavaModelException thrown when the compilation unit could not be accessed. + */ + public static ImportRewrite create(ICompilationUnit cu, boolean restoreExistingImports) throws JavaModelException { + if (cu == null) { + throw new IllegalArgumentException("Compilation unit must not be null"); //$NON-NLS-1$ + } + List existingImport= null; + if (restoreExistingImports) { + existingImport= new ArrayList(); + IImportDeclaration[] imports= cu.getImports(); + for (int i= 0; i < imports.length; i++) { + IImportDeclaration curr= imports[i]; + char prefix= Flags.isStatic(curr.getFlags()) ? STATIC_PREFIX : NORMAL_PREFIX; + existingImport.add(prefix + curr.getElementName()); + } + } + return new ImportRewrite(cu, null, existingImport); + } + + /** + * Creates a {@link ImportRewrite} from a an AST ({@link CompilationUnit}). The AST has to be created from a + * {@link ICompilationUnit}, that means {@link ASTParser#setSource(ICompilationUnit)} has been used when creating the + * AST. If <code>restoreExistingImports</code> is <code>true</code>, all existing imports are kept, and new imports + * will be inserted at best matching locations. If <code>restoreExistingImports</code> is <code>false</code>, the + * existing imports will be removed and only the newly added imports will be created. + * <p> + * Note that this method is more efficient than using {@link #create(ICompilationUnit, boolean)} if an AST is already available. + * </p> + * @param astRoot the AST root node to create the imports for + * @param restoreExistingImports specifies if the existing imports should be kept or removed. + * @return the created import rewriter. + * @throws IllegalArgumentException thrown when the passed AST is null or was not created from a compilation unit. + */ + public static ImportRewrite create(CompilationUnit astRoot, boolean restoreExistingImports) { + if (astRoot == null) { + throw new IllegalArgumentException("AST must not be null"); //$NON-NLS-1$ + } + ITypeRoot typeRoot = astRoot.getTypeRoot(); + if (!(typeRoot instanceof ICompilationUnit)) { + throw new IllegalArgumentException("AST must have been constructed from a Java element"); //$NON-NLS-1$ + } + List existingImport= null; + if (restoreExistingImports) { + existingImport= new ArrayList(); + List imports= astRoot.imports(); + for (int i= 0; i < imports.size(); i++) { + ImportDeclaration curr= (ImportDeclaration) imports.get(i); + StringBuffer buf= new StringBuffer(); + buf.append(curr.isStatic() ? STATIC_PREFIX : NORMAL_PREFIX).append(curr.getName().getFullyQualifiedName()); + if (curr.isOnDemand()) { + if (buf.length() > 1) + buf.append('.'); + buf.append('*'); + } + existingImport.add(buf.toString()); + } + } + return new ImportRewrite((ICompilationUnit) typeRoot, astRoot, existingImport); + } + + private ImportRewrite(ICompilationUnit cu, CompilationUnit astRoot, List existingImports) { + this.compilationUnit= cu; + this.astRoot= astRoot; // might be null + if (existingImports != null) { + this.existingImports= existingImports; + this.restoreExistingImports= !existingImports.isEmpty(); + } else { + this.existingImports= new ArrayList(); + this.restoreExistingImports= false; + } + this.filterImplicitImports= true; + + this.defaultContext= new ImportRewriteContext() { + public int findInContext(String qualifier, String name, int kind) { + return findInImports(qualifier, name, kind); + } + }; + this.addedImports= null; // Initialized on use + this.removedImports= null; // Initialized on use + this.createdImports= null; + this.createdStaticImports= null; +//{ObjectTeams: + this.importsToMarkAsBase = null; +// SH} + + this.importOrder= CharOperation.NO_STRINGS; + this.importOnDemandThreshold= 99; + this.staticImportOnDemandThreshold= 99; + + this.importsKindMap = new HashMap(); + } + + + /** + * Defines the import groups and order to be used by the {@link ImportRewrite}. + * Imports are added to the group matching their qualified name most. The empty group name groups all imports not matching + * any other group. Static imports are managed in separate groups. Static import group names are prefixed with a '#' character. + * @param order A list of strings defining the import groups. A group name must be a valid package name or empty. If can be + * prefixed by the '#' character for static import groups + */ + public void setImportOrder(String[] order) { + if (order == null) + throw new IllegalArgumentException("Order must not be null"); //$NON-NLS-1$ + this.importOrder= order; + } + + /** + * Sets the on-demand import threshold for normal (non-static) imports. + * This threshold defines the number of imports that need to be in a group to use + * a on-demand (star) import declaration instead. + * + * @param threshold a positive number defining the on-demand import threshold + * for normal (non-static) imports. + * @throws IllegalArgumentException a {@link IllegalArgumentException} is thrown + * if the number is not positive. + */ + public void setOnDemandImportThreshold(int threshold) { + if (threshold <= 0) + throw new IllegalArgumentException("Threshold must be positive."); //$NON-NLS-1$ + this.importOnDemandThreshold= threshold; + } + + /** + * Sets the on-demand import threshold for static imports. + * This threshold defines the number of imports that need to be in a group to use + * a on-demand (star) import declaration instead. + * + * @param threshold a positive number defining the on-demand import threshold + * for normal (non-static) imports. + * @throws IllegalArgumentException a {@link IllegalArgumentException} is thrown + * if the number is not positive. + */ + public void setStaticOnDemandImportThreshold(int threshold) { + if (threshold <= 0) + throw new IllegalArgumentException("Threshold must be positive."); //$NON-NLS-1$ + this.staticImportOnDemandThreshold= threshold; + } + + /** + * The compilation unit for which this import rewrite was created for. + * @return the compilation unit for which this import rewrite was created for. + */ + public ICompilationUnit getCompilationUnit() { + return this.compilationUnit; + } + + /** + * Returns the default rewrite context that only knows about the imported types. Clients + * can write their own context and use the default context for the default behavior. + * @return the default import rewrite context. + */ + public ImportRewriteContext getDefaultImportRewriteContext() { + return this.defaultContext; + } + + /** + * Specifies that implicit imports (types in default package, package <code>java.lang</code> or + * in the same package as the rewrite compilation unit should not be created except if necessary + * to resolve an on-demand import conflict. The filter is enabled by default. + * @param filterImplicitImports if set, implicit imports will be filtered. + */ + public void setFilterImplicitImports(boolean filterImplicitImports) { + this.filterImplicitImports= filterImplicitImports; + } + + private static int compareImport(char prefix, String qualifier, String name, String curr) { + if (curr.charAt(0) != prefix || !curr.endsWith(name)) { + return ImportRewriteContext.RES_NAME_UNKNOWN; + } + + curr= curr.substring(1); // remove the prefix + + if (curr.length() == name.length()) { + if (qualifier.length() == 0) { + return ImportRewriteContext.RES_NAME_FOUND; + } + return ImportRewriteContext.RES_NAME_CONFLICT; + } + // at this place: curr.length > name.length + + int dotPos= curr.length() - name.length() - 1; + if (curr.charAt(dotPos) != '.') { + return ImportRewriteContext.RES_NAME_UNKNOWN; + } + if (qualifier.length() != dotPos || !curr.startsWith(qualifier)) { + return ImportRewriteContext.RES_NAME_CONFLICT; + } + return ImportRewriteContext.RES_NAME_FOUND; + } + + /** + * Not API, package visibility as accessed from an anonymous type + */ + /* package */ final int findInImports(String qualifier, String name, int kind) { + boolean allowAmbiguity= (kind == ImportRewriteContext.KIND_STATIC_METHOD) || (name.length() == 1 && name.charAt(0) == '*'); + List imports= this.existingImports; + char prefix= (kind == ImportRewriteContext.KIND_TYPE) ? NORMAL_PREFIX : STATIC_PREFIX; + + for (int i= imports.size() - 1; i >= 0 ; i--) { + String curr= (String) imports.get(i); + int res= compareImport(prefix, qualifier, name, curr); + if (res != ImportRewriteContext.RES_NAME_UNKNOWN) { + if (!allowAmbiguity || res == ImportRewriteContext.RES_NAME_FOUND) { + if (prefix != STATIC_PREFIX) { + return res; + } + Object currKind = this.importsKindMap.get(curr.substring(1)); + if (currKind != null && currKind.equals(this.importsKindMap.get(qualifier + '.' + name))) { + return res; + } + } + } + } + return ImportRewriteContext.RES_NAME_UNKNOWN; + } + + /** + * Adds a new import to the rewriter's record and returns a {@link Type} node that can be used + * in the code as a reference to the type. The type binding can be an array binding, type variable or wildcard. + * If the binding is a generic type, the type parameters are ignored. For parameterized types, also the type + * arguments are processed and imports added if necessary. Anonymous types inside type arguments are normalized to their base type, wildcard + * of wildcards are ignored. + * <p> + * No imports are added for types that are already known. If a import for a type is recorded to be removed, this record is discarded instead. + * </p> + * <p> + * The content of the compilation unit itself is actually not modified + * in any way by this method; rather, the rewriter just records that a new import has been added. + * </p> + * @param typeSig the signature of the type to be added. + * @param ast the AST to create the returned type for. + * @return returns a type to which the type binding can be assigned to. The returned type contains is unqualified + * when an import could be added or was already known. It is fully qualified, if an import conflict prevented the import. + */ + public Type addImportFromSignature(String typeSig, AST ast) { + return addImportFromSignature(typeSig, ast, this.defaultContext); + } + + /** + * Adds a new import to the rewriter's record and returns a {@link Type} node that can be used + * in the code as a reference to the type. The type binding can be an array binding, type variable or wildcard. + * If the binding is a generic type, the type parameters are ignored. For parameterized types, also the type + * arguments are processed and imports added if necessary. Anonymous types inside type arguments are normalized to their base type, wildcard + * of wildcards are ignored. + * <p> + * No imports are added for types that are already known. If a import for a type is recorded to be removed, this record is discarded instead. + * </p> + * <p> + * The content of the compilation unit itself is actually not modified + * in any way by this method; rather, the rewriter just records that a new import has been added. + * </p> + * @param typeSig the signature of the type to be added. + * @param ast the AST to create the returned type for. + * @param context an optional context that knows about types visible in the current scope or <code>null</code> + * to use the default context only using the available imports. + * @return returns a type to which the type binding can be assigned to. The returned type contains is unqualified + * when an import could be added or was already known. It is fully qualified, if an import conflict prevented the import. + */ + public Type addImportFromSignature(String typeSig, AST ast, ImportRewriteContext context) { + if (typeSig == null || typeSig.length() == 0) { + throw new IllegalArgumentException("Invalid type signature: empty or null"); //$NON-NLS-1$ + } + int sigKind= Signature.getTypeSignatureKind(typeSig); + switch (sigKind) { + case Signature.BASE_TYPE_SIGNATURE: + return ast.newPrimitiveType(PrimitiveType.toCode(Signature.toString(typeSig))); + case Signature.ARRAY_TYPE_SIGNATURE: + Type elementType= addImportFromSignature(Signature.getElementType(typeSig), ast, context); + return ast.newArrayType(elementType, Signature.getArrayCount(typeSig)); + case Signature.CLASS_TYPE_SIGNATURE: + String erasureSig= Signature.getTypeErasure(typeSig); + + String erasureName= Signature.toString(erasureSig); + if (erasureSig.charAt(0) == Signature.C_RESOLVED) { + erasureName= internalAddImport(erasureName, context); + } + Type baseType= ast.newSimpleType(ast.newName(erasureName)); + String[] typeArguments= Signature.getTypeArguments(typeSig); + if (typeArguments.length > 0) { + ParameterizedType type= ast.newParameterizedType(baseType); + List argNodes= type.typeArguments(); + for (int i= 0; i < typeArguments.length; i++) { + String curr= typeArguments[i]; + if (containsNestedCapture(curr)) { // see bug 103044 + argNodes.add(ast.newWildcardType()); + } else { + argNodes.add(addImportFromSignature(curr, ast, context)); + } + } + return type; + } + return baseType; + case Signature.TYPE_VARIABLE_SIGNATURE: + return ast.newSimpleType(ast.newSimpleName(Signature.toString(typeSig))); + case Signature.WILDCARD_TYPE_SIGNATURE: + WildcardType wildcardType= ast.newWildcardType(); + char ch= typeSig.charAt(0); + if (ch != Signature.C_STAR) { + Type bound= addImportFromSignature(typeSig.substring(1), ast, context); + wildcardType.setBound(bound, ch == Signature.C_EXTENDS); + } + return wildcardType; + case Signature.CAPTURE_TYPE_SIGNATURE: + return addImportFromSignature(typeSig.substring(1), ast, context); + default: + throw new IllegalArgumentException("Unknown type signature kind: " + typeSig); //$NON-NLS-1$ + } + } + + + + /** + * Adds a new import to the rewriter's record and returns a type reference that can be used + * in the code. The type binding can be an array binding, type variable or wildcard. + * If the binding is a generic type, the type parameters are ignored. For parameterized types, also the type + * arguments are processed and imports added if necessary. Anonymous types inside type arguments are normalized to their base type, wildcard + * of wildcards are ignored. + * <p> + * No imports are added for types that are already known. If a import for a type is recorded to be removed, this record is discarded instead. + * </p> + * <p> + * The content of the compilation unit itself is actually not modified + * in any way by this method; rather, the rewriter just records that a new import has been added. + * </p> + * @param binding the signature of the type to be added. + * @return returns a type to which the type binding can be assigned to. The returned type contains is unqualified + * when an import could be added or was already known. It is fully qualified, if an import conflict prevented the import. + */ + public String addImport(ITypeBinding binding) { + return addImport(binding, this.defaultContext); + } + + /** + * Adds a new import to the rewriter's record and returns a type reference that can be used + * in the code. The type binding can be an array binding, type variable or wildcard. + * If the binding is a generic type, the type parameters are ignored. For parameterized types, also the type + * arguments are processed and imports added if necessary. Anonymous types inside type arguments are normalized to their base type, wildcard + * of wildcards are ignored. + * <p> + * No imports are added for types that are already known. If a import for a type is recorded to be removed, this record is discarded instead. + * </p> + * <p> + * The content of the compilation unit itself is actually not modified + * in any way by this method; rather, the rewriter just records that a new import has been added. + * </p> + * @param binding the signature of the type to be added. + * @param context an optional context that knows about types visible in the current scope or <code>null</code> + * to use the default context only using the available imports. + * @return returns a type to which the type binding can be assigned to. The returned type contains is unqualified + * when an import could be added or was already known. It is fully qualified, if an import conflict prevented the import. + */ + public String addImport(ITypeBinding binding, ImportRewriteContext context) { + if (binding.isPrimitive() || binding.isTypeVariable() || binding.isRecovered()) { + return binding.getName(); + } + + ITypeBinding normalizedBinding= normalizeTypeBinding(binding); + if (normalizedBinding == null) { + return "invalid"; //$NON-NLS-1$ + } + if (normalizedBinding.isWildcardType()) { + StringBuffer res= new StringBuffer("?"); //$NON-NLS-1$ + ITypeBinding bound= normalizedBinding.getBound(); + if (bound != null && !bound.isWildcardType() && !bound.isCapture()) { // bug 95942 + if (normalizedBinding.isUpperbound()) { + res.append(" extends "); //$NON-NLS-1$ + } else { + res.append(" super "); //$NON-NLS-1$ + } + res.append(addImport(bound, context)); + } + return res.toString(); + } + + if (normalizedBinding.isArray()) { + StringBuffer res= new StringBuffer(addImport(normalizedBinding.getElementType(), context)); + for (int i= normalizedBinding.getDimensions(); i > 0; i--) { + res.append("[]"); //$NON-NLS-1$ + } + return res.toString(); + } + + String qualifiedName= getRawQualifiedName(normalizedBinding); + if (qualifiedName.length() > 0) { +//{ObjectTeams: silently refuse to import a role type: +/* orig: + String str= internalAddImport(qualifiedName, context); + :giro */ + String str= importRefusingRole(binding, qualifiedName, context); +// SH} + + + ITypeBinding[] typeArguments= normalizedBinding.getTypeArguments(); + if (typeArguments.length > 0) { + StringBuffer res= new StringBuffer(str); + res.append('<'); + for (int i= 0; i < typeArguments.length; i++) { + if (i > 0) { + res.append(','); + } + ITypeBinding curr= typeArguments[i]; + if (containsNestedCapture(curr, false)) { // see bug 103044 + res.append('?'); + } else { + res.append(addImport(curr, context)); + } + } + res.append('>'); + return res.toString(); + } + return str; + } + return getRawName(normalizedBinding); + } + + private boolean containsNestedCapture(ITypeBinding binding, boolean isNested) { + if (binding == null || binding.isPrimitive() || binding.isTypeVariable()) { + return false; + } + if (binding.isCapture()) { + if (isNested) { + return true; + } + return containsNestedCapture(binding.getWildcard(), true); + } + if (binding.isWildcardType()) { + return containsNestedCapture(binding.getBound(), true); + } + if (binding.isArray()) { + return containsNestedCapture(binding.getElementType(), true); + } + ITypeBinding[] typeArguments= binding.getTypeArguments(); + for (int i= 0; i < typeArguments.length; i++) { + if (containsNestedCapture(typeArguments[i], true)) { + return true; + } + } + return false; + } + + private boolean containsNestedCapture(String signature) { + return signature.length() > 1 && signature.indexOf(Signature.C_CAPTURE, 1) != -1; + } + + private static ITypeBinding normalizeTypeBinding(ITypeBinding binding) { + if (binding != null && !binding.isNullType() && !"void".equals(binding.getName())) { //$NON-NLS-1$ + if (binding.isAnonymous()) { + ITypeBinding[] baseBindings= binding.getInterfaces(); + if (baseBindings.length > 0) { + return baseBindings[0]; + } + return binding.getSuperclass(); + } + if (binding.isCapture()) { + return binding.getWildcard(); + } + return binding; + } + return null; + } + + /** + * Adds a new import to the rewriter's record and returns a {@link Type} that can be used + * in the code. The type binding can be an array binding, type variable or wildcard. + * If the binding is a generic type, the type parameters are ignored. For parameterized types, also the type + * arguments are processed and imports added if necessary. Anonymous types inside type arguments are normalized to their base type, wildcard + * of wildcards are ignored. + * <p> + * No imports are added for types that are already known. If a import for a type is recorded to be removed, this record is discarded instead. + * </p> + * <p> + * The content of the compilation unit itself is actually not modified + * in any way by this method; rather, the rewriter just records that a new import has been added. + * </p> + * @param binding the signature of the type to be added. + * @param ast the AST to create the returned type for. + * @return returns a type to which the type binding can be assigned to. The returned type contains is unqualified + * when an import could be added or was already known. It is fully qualified, if an import conflict prevented the import. + */ + public Type addImport(ITypeBinding binding, AST ast) { + return addImport(binding, ast, this.defaultContext); + } + + /** + * Adds a new import to the rewriter's record and returns a {@link Type} that can be used + * in the code. The type binding can be an array binding, type variable or wildcard. + * If the binding is a generic type, the type parameters are ignored. For parameterized types, also the type + * arguments are processed and imports added if necessary. Anonymous types inside type arguments are normalized to their base type, wildcard + * of wildcards are ignored. + * <p> + * No imports are added for types that are already known. If a import for a type is recorded to be removed, this record is discarded instead. + * </p> + * <p> + * The content of the compilation unit itself is actually not modified + * in any way by this method; rather, the rewriter just records that a new import has been added. + * </p> + * @param binding the signature of the type to be added. + * @param ast the AST to create the returned type for. + * @param context an optional context that knows about types visible in the current scope or <code>null</code> + * to use the default context only using the available imports. + * @return returns a type to which the type binding can be assigned to. The returned type contains is unqualified + * when an import could be added or was already known. It is fully qualified, if an import conflict prevented the import. + */ + public Type addImport(ITypeBinding binding, AST ast, ImportRewriteContext context) { + if (binding.isPrimitive()) { + return ast.newPrimitiveType(PrimitiveType.toCode(binding.getName())); + } + + ITypeBinding normalizedBinding= normalizeTypeBinding(binding); + if (normalizedBinding == null) { + return ast.newSimpleType(ast.newSimpleName("invalid")); //$NON-NLS-1$ + } + + if (normalizedBinding.isTypeVariable()) { + // no import + return ast.newSimpleType(ast.newSimpleName(binding.getName())); + } + if (normalizedBinding.isWildcardType()) { + WildcardType wcType= ast.newWildcardType(); + ITypeBinding bound= normalizedBinding.getBound(); + if (bound != null && !bound.isWildcardType() && !bound.isCapture()) { // bug 96942 + Type boundType= addImport(bound, ast, context); + wcType.setBound(boundType, normalizedBinding.isUpperbound()); + } + return wcType; + } + + if (normalizedBinding.isArray()) { + Type elementType= addImport(normalizedBinding.getElementType(), ast, context); + return ast.newArrayType(elementType, normalizedBinding.getDimensions()); + } + + String qualifiedName= getRawQualifiedName(normalizedBinding); + if (qualifiedName.length() > 0) { +//{ObjectTeams: silently refuse to import a role type: +/* orig: + String res= internalAddImport(qualifiedName, context); + :giro */ + String res= importRefusingRole(binding, qualifiedName, context); +// SH} + + ITypeBinding[] typeArguments= normalizedBinding.getTypeArguments(); + if (typeArguments.length > 0) { + Type erasureType= ast.newSimpleType(ast.newName(res)); + ParameterizedType paramType= ast.newParameterizedType(erasureType); + List arguments= paramType.typeArguments(); + for (int i= 0; i < typeArguments.length; i++) { + ITypeBinding curr= typeArguments[i]; + if (containsNestedCapture(curr, false)) { // see bug 103044 + arguments.add(ast.newWildcardType()); + } else { + arguments.add(addImport(curr, ast, context)); + } + } + return paramType; + } +/* orig: + return ast.newSimpleType(ast.newName(res)); + :giro */ + Type type = ast.newSimpleType(ast.newName(res)); + if (binding.isDependentType(true)) { + // ignoring value parameters would introduce type errors in refactorings. + String[] segments = binding.getAnchorPath(); + if (segments.length > 0) { + ParameterizedType pType = ast.newParameterizedType(type); + pType.typeArguments().add(ast.newTypeAnchor(ast.newName(segments))); + type = pType; + } + } + return type; + } + return ast.newSimpleType(ast.newName(getRawName(normalizedBinding))); + } + +//{ObjectTeams: try to add an import but refuse if binding is a role. + private String importRefusingRole(ITypeBinding binding, String qualifiedName, ImportRewriteContext context) { + String res= qualifiedName; + if (binding.isRole()) { // still need to extract the simple name + int pos = qualifiedName.lastIndexOf('.'); + if (pos > -1) + res= qualifiedName.substring(pos+1); + } else + res= internalAddImport(qualifiedName, context); + return res; + } +// SH} + + /** + * Adds a new import to the rewriter's record and returns a type reference that can be used + * in the code. The type binding can only be an array or non-generic type. + * <p> + * No imports are added for types that are already known. If a import for a type is recorded to be removed, this record is discarded instead. + * </p> + * <p> + * The content of the compilation unit itself is actually not modified + * in any way by this method; rather, the rewriter just records that a new import has been added. + * </p> + * @param qualifiedTypeName the qualified type name of the type to be added + * @param context an optional context that knows about types visible in the current scope or <code>null</code> + * to use the default context only using the available imports. + * @return returns a type to which the type binding can be assigned to. The returned type contains is unqualified + * when an import could be added or was already known. It is fully qualified, if an import conflict prevented the import. + */ + public String addImport(String qualifiedTypeName, ImportRewriteContext context) { + int angleBracketOffset= qualifiedTypeName.indexOf('<'); + if (angleBracketOffset != -1) { + return internalAddImport(qualifiedTypeName.substring(0, angleBracketOffset), context) + qualifiedTypeName.substring(angleBracketOffset); + } + int bracketOffset= qualifiedTypeName.indexOf('['); + if (bracketOffset != -1) { + return internalAddImport(qualifiedTypeName.substring(0, bracketOffset), context) + qualifiedTypeName.substring(bracketOffset); + } + return internalAddImport(qualifiedTypeName, context); + } + + /** + * Adds a new import to the rewriter's record and returns a type reference that can be used + * in the code. The type binding can only be an array or non-generic type. + * <p> + * No imports are added for types that are already known. If a import for a type is recorded to be removed, this record is discarded instead. + * </p> + * <p> + * The content of the compilation unit itself is actually not modified + * in any way by this method; rather, the rewriter just records that a new import has been added. + * </p> + * @param qualifiedTypeName the qualified type name of the type to be added + * @return returns a type to which the type binding can be assigned to. The returned type contains is unqualified + * when an import could be added or was already known. It is fully qualified, if an import conflict prevented the import. + */ + public String addImport(String qualifiedTypeName) { + return addImport(qualifiedTypeName, this.defaultContext); + } + + /** + * Adds a new static import to the rewriter's record and returns a reference that can be used in the code. The reference will + * be fully qualified if an import conflict prevented the import or unqualified if the import succeeded or was already + * existing. + * <p> + * No imports are added for members that are already known. If a import for a type is recorded to be removed, this record is discarded instead. + * </p> + * <p> + * The content of the compilation unit itself is actually not modified + * in any way by this method; rather, the rewriter just records that a new import has been added. + * </p> + * @param binding The binding of the static field or method to be added. + * @return returns either the simple member name if the import was successful or else the qualified name if + * an import conflict prevented the import. + * @throws IllegalArgumentException an {@link IllegalArgumentException} is thrown if the binding is not a static field + * or method. + */ + public String addStaticImport(IBinding binding) { + return addStaticImport(binding, this.defaultContext); + } + + /** + * Adds a new static import to the rewriter's record and returns a reference that can be used in the code. The reference will + * be fully qualified if an import conflict prevented the import or unqualified if the import succeeded or was already + * existing. + * <p> + * No imports are added for members that are already known. If a import for a type is recorded to be removed, this record is discarded instead. + * </p> + * <p> + * The content of the compilation unit itself is actually not modified + * in any way by this method; rather, the rewriter just records that a new import has been added. + * </p> + * @param binding The binding of the static field or method to be added. + * @param context an optional context that knows about members visible in the current scope or <code>null</code> + * to use the default context only using the available imports. + * @return returns either the simple member name if the import was successful or else the qualified name if + * an import conflict prevented the import. + * @throws IllegalArgumentException an {@link IllegalArgumentException} is thrown if the binding is not a static field + * or method. + */ + public String addStaticImport(IBinding binding, ImportRewriteContext context) { + if (Modifier.isStatic(binding.getModifiers())) { + if (binding instanceof IVariableBinding) { + IVariableBinding variableBinding= (IVariableBinding) binding; + if (variableBinding.isField()) { + ITypeBinding declaringType= variableBinding.getDeclaringClass(); + return addStaticImport(getRawQualifiedName(declaringType), binding.getName(), true, context); + } + } else if (binding instanceof IMethodBinding) { + ITypeBinding declaringType= ((IMethodBinding) binding).getDeclaringClass(); + return addStaticImport(getRawQualifiedName(declaringType), binding.getName(), false, context); + } + } + throw new IllegalArgumentException("Binding must be a static field or method."); //$NON-NLS-1$ + } + + /** + * Adds a new static import to the rewriter's record and returns a reference that can be used in the code. The reference will + * be fully qualified if an import conflict prevented the import or unqualified if the import succeeded or was already + * existing. + * <p> + * No imports are added for members that are already known. If a import for a type is recorded to be removed, this record is discarded instead. + * </p> + * <p> + * The content of the compilation unit itself is actually not modified + * in any way by this method; rather, the rewriter just records that a new import has been added. + * </p> + * @param declaringTypeName The qualified name of the static's member declaring type + * @param simpleName the simple name of the member; either a field or a method name. + * @param isField <code>true</code> specifies that the member is a field, <code>false</code> if it is a + * method. + * @return returns either the simple member name if the import was successful or else the qualified name if + * an import conflict prevented the import. + */ + public String addStaticImport(String declaringTypeName, String simpleName, boolean isField) { + return addStaticImport(declaringTypeName, simpleName, isField, this.defaultContext); + } + + /** + * Adds a new static import to the rewriter's record and returns a reference that can be used in the code. The reference will + * be fully qualified if an import conflict prevented the import or unqualified if the import succeeded or was already + * existing. + * <p> + * No imports are added for members that are already known. If a import for a type is recorded to be removed, this record is discarded instead. + * </p> + * <p> + * The content of the compilation unit itself is actually not modified + * in any way by this method; rather, the rewriter just records that a new import has been added. + * </p> + * @param declaringTypeName The qualified name of the static's member declaring type + * @param simpleName the simple name of the member; either a field or a method name. + * @param isField <code>true</code> specifies that the member is a field, <code>false</code> if it is a + * method. + * @param context an optional context that knows about members visible in the current scope or <code>null</code> + * to use the default context only using the available imports. + * @return returns either the simple member name if the import was successful or else the qualified name if + * an import conflict prevented the import. + */ + public String addStaticImport(String declaringTypeName, String simpleName, boolean isField, ImportRewriteContext context) { + String key = declaringTypeName + '.' + simpleName; + if (declaringTypeName.indexOf('.') == -1) { + return key; + } + if (context == null) { + context= this.defaultContext; + } + int kind= isField ? ImportRewriteContext.KIND_STATIC_FIELD : ImportRewriteContext.KIND_STATIC_METHOD; + this.importsKindMap.put(key, new Integer(kind)); + int res= context.findInContext(declaringTypeName, simpleName, kind); + if (res == ImportRewriteContext.RES_NAME_CONFLICT) { + return key; + } + if (res == ImportRewriteContext.RES_NAME_UNKNOWN) { + addEntry(STATIC_PREFIX + key); + } + return simpleName; + } + + private String internalAddImport(String fullTypeName, ImportRewriteContext context) { + int idx= fullTypeName.lastIndexOf('.'); + String typeContainerName, typeName; + if (idx != -1) { + typeContainerName= fullTypeName.substring(0, idx); + typeName= fullTypeName.substring(idx + 1); + } else { + typeContainerName= ""; //$NON-NLS-1$ + typeName= fullTypeName; + } + + if (typeContainerName.length() == 0 && PrimitiveType.toCode(typeName) != null) { + return fullTypeName; + } + + if (context == null) + context= this.defaultContext; + + int res= context.findInContext(typeContainerName, typeName, ImportRewriteContext.KIND_TYPE); + if (res == ImportRewriteContext.RES_NAME_CONFLICT) { + return fullTypeName; + } + if (res == ImportRewriteContext.RES_NAME_UNKNOWN) { + addEntry(NORMAL_PREFIX + fullTypeName); + } + return typeName; + } + + private void addEntry(String entry) { + this.existingImports.add(entry); + + if (this.removedImports != null) { + if (this.removedImports.remove(entry)) { + return; + } + } + + if (this.addedImports == null) { + this.addedImports= new ArrayList(); + } + this.addedImports.add(entry); + } + + private boolean removeEntry(String entry) { + if (this.existingImports.remove(entry)) { + if (this.addedImports != null) { + if (this.addedImports.remove(entry)) { + return true; + } + } + if (this.removedImports == null) { + this.removedImports= new ArrayList(); + } + this.removedImports.add(entry); + return true; + } + return false; + } + + /** + * Records to remove a import. No remove is recorded if no such import exists or if such an import is recorded + * to be added. In that case the record of the addition is discarded. + * <p> + * The content of the compilation unit itself is actually not modified + * in any way by this method; rather, the rewriter just records that an import has been removed. + * </p> + * @param qualifiedName The import name to remove. + * @return <code>true</code> is returned of an import of the given name could be found. + */ + public boolean removeImport(String qualifiedName) { + return removeEntry(NORMAL_PREFIX + qualifiedName); + } + + /** + * Records to remove a static import. No remove is recorded if no such import exists or if such an import is recorded + * to be added. In that case the record of the addition is discarded. + * <p> + * The content of the compilation unit itself is actually not modified + * in any way by this method; rather, the rewriter just records that a new import has been removed. + * </p> + * @param qualifiedName The import name to remove. + * @return <code>true</code> is returned of an import of the given name could be found. + */ + public boolean removeStaticImport(String qualifiedName) { + return removeEntry(STATIC_PREFIX + qualifiedName); + } + + private static String getRawName(ITypeBinding normalizedBinding) { + return normalizedBinding.getTypeDeclaration().getName(); + } + + private static String getRawQualifiedName(ITypeBinding normalizedBinding) { + return normalizedBinding.getTypeDeclaration().getQualifiedName(); + } + + + /** + * Converts all modifications recorded by this rewriter into an object representing the corresponding text + * edits to the source code of the rewrite's compilation unit. The compilation unit itself is not modified. + * <p> + * Calling this methods does not discard the modifications on record. Subsequence modifications are added + * to the ones already on record. If this method is called again later, the resulting text edit object will accurately + * reflect the net cumulative affect of all those changes. + * </p> + * @param monitor the progress monitor or <code>null</code> + * @return text edit object describing the changes to the document corresponding to the changes + * recorded by this rewriter + * @throws CoreException the exception is thrown if the rewrite fails. + */ + public final TextEdit rewriteImports(IProgressMonitor monitor) throws CoreException { + if (monitor == null) { + monitor= new NullProgressMonitor(); + } + + try { + monitor.beginTask(Messages.bind(Messages.importRewrite_processDescription), 2); + if (!hasRecordedChanges()) { + this.createdImports= CharOperation.NO_STRINGS; + this.createdStaticImports= CharOperation.NO_STRINGS; + return new MultiTextEdit(); + } + + CompilationUnit usedAstRoot= this.astRoot; + if (usedAstRoot == null) { + ASTParser parser= ASTParser.newParser(AST.JLS3); + parser.setSource(this.compilationUnit); + parser.setFocalPosition(0); // reduced AST + parser.setResolveBindings(false); + usedAstRoot= (CompilationUnit) parser.createAST(new SubProgressMonitor(monitor, 1)); + } + + ImportRewriteAnalyzer computer= new ImportRewriteAnalyzer(this.compilationUnit, usedAstRoot, this.importOrder, this.importOnDemandThreshold, this.staticImportOnDemandThreshold, this.restoreExistingImports); + computer.setFilterImplicitImports(this.filterImplicitImports); + + if (this.addedImports != null) { + for (int i= 0; i < this.addedImports.size(); i++) { + String curr= (String) this.addedImports.get(i); +//{ObjectTeams: base import: + if (BASE_PREFIX == curr.charAt(0)) + computer.addBaseImport(curr.substring(1)); + else + computer.addImport(curr.substring(1), STATIC_PREFIX == curr.charAt(0), /*isBase*/false); + /* orig: + computer.addImport(curr.substring(1), STATIC_PREFIX == curr.charAt(0)); + :giro */ +// SH} + } + } + + if (this.removedImports != null) { + for (int i= 0; i < this.removedImports.size(); i++) { + String curr= (String) this.removedImports.get(i); +//{ObjectTeams: added isBase arg: +/* orig: + computer.removeImport(curr.substring(1), STATIC_PREFIX == curr.charAt(0)); + :giro */ + computer.removeImport(curr.substring(1), STATIC_PREFIX == curr.charAt(0), BASE_PREFIX == curr.charAt(0)); +// SH} + } + } +//{ObjectTeams: import base: + if (this.importsToMarkAsBase != null) { + for (int i= 0; i < this.importsToMarkAsBase.size(); i++) { + String curr = this.importsToMarkAsBase.get(i); + computer.setBase(curr); + } + } +// SH} + + TextEdit result= computer.getResultingEdits(new SubProgressMonitor(monitor, 1)); + this.createdImports= computer.getCreatedImports(); + this.createdStaticImports= computer.getCreatedStaticImports(); + return result; + } finally { + monitor.done(); + } + } + + /** + * Returns all new non-static imports created by the last invocation of {@link #rewriteImports(IProgressMonitor)} + * or <code>null</code> if these methods have not been called yet. + * <p> + * Note that this list doesn't need to be the same as the added imports (see {@link #getAddedImports()}) as + * implicit imports are not created and some imports are represented by on-demand imports instead. + * </p> + * @return the created imports + */ + public String[] getCreatedImports() { + return this.createdImports; + } + + /** + * Returns all new static imports created by the last invocation of {@link #rewriteImports(IProgressMonitor)} + * or <code>null</code> if these methods have not been called yet. + * <p> + * Note that this list doesn't need to be the same as the added static imports ({@link #getAddedStaticImports()}) as + * implicit imports are not created and some imports are represented by on-demand imports instead. + * </p + * @return the created imports + */ + public String[] getCreatedStaticImports() { + return this.createdStaticImports; + } + + /** + * Returns all non-static imports that are recorded to be added. + * + * @return the imports recorded to be added. + */ + public String[] getAddedImports() { + return filterFromList(this.addedImports, NORMAL_PREFIX); + } + + /** + * Returns all static imports that are recorded to be added. + * + * @return the static imports recorded to be added. + */ + public String[] getAddedStaticImports() { + return filterFromList(this.addedImports, STATIC_PREFIX); + } + + /** + * Returns all non-static imports that are recorded to be removed. + * + * @return the imports recorded to be removed. + */ + public String[] getRemovedImports() { + return filterFromList(this.removedImports, NORMAL_PREFIX); + } + + /** + * Returns all static imports that are recorded to be removed. + * + * @return the static imports recorded to be removed. + */ + public String[] getRemovedStaticImports() { + return filterFromList(this.removedImports, STATIC_PREFIX); + } + + /** + * Returns <code>true</code> if imports have been recorded to be added or removed. + * @return boolean returns if any changes to imports have been recorded. + */ + public boolean hasRecordedChanges() { + return !this.restoreExistingImports || + (this.addedImports != null && !this.addedImports.isEmpty()) || +//{ObjectTeams: + (this.importsToMarkAsBase != null && !this.importsToMarkAsBase.isEmpty()) || +// SH} + (this.removedImports != null && !this.removedImports.isEmpty()); + } + +//{ObjectTeams: my version of above in anticipation of https://bugs.eclipse.org/bugs/show_bug.cgi?id=271812 + public boolean myHasRecordedChanges() { + return + (this.addedImports != null && !this.addedImports.isEmpty()) || +//{ObjectTeams: + (this.importsToMarkAsBase != null && !this.importsToMarkAsBase.isEmpty()) || +// SH} + (this.removedImports != null && !this.removedImports.isEmpty()); + } +// SH} + + private static String[] filterFromList(List imports, char prefix) { + if (imports == null) { + return CharOperation.NO_STRINGS; + } + ArrayList res= new ArrayList(); + for (int i= 0; i < imports.size(); i++) { + String curr= (String) imports.get(i); + if (prefix == curr.charAt(0)) { + res.add(curr.substring(1)); + } + } + return (String[]) res.toArray(new String[res.size()]); + } + +//{ObjectTeams: import base (not like the others, since this only changes an existing import). + public boolean setImportBase(IBinding binding) { + if (!(binding instanceof ITypeBinding)) + throw new IllegalArgumentException("Binding must be a type."); //$NON-NLS-1$ + return setImportBase(((ITypeBinding)binding).getQualifiedName(), this.defaultContext); + } + + public boolean setImportBase(String qualifiedTypeName, ImportRewriteContext context) { + int lastDot = qualifiedTypeName.lastIndexOf('.'); + if (lastDot == -1) { + return false; + } + if (context == null) { + context= this.defaultContext; + } + int kind= ImportRewriteContext.KIND_TYPE; + String qualifier = qualifiedTypeName.substring(0, lastDot); + String simpleName = qualifiedTypeName.substring(lastDot+1); + int res= context.findInContext(qualifier, simpleName, kind); + if (res == ImportRewriteContext.RES_NAME_CONFLICT) { + return false; + } + if (res == ImportRewriteContext.RES_NAME_FOUND) { + if (this.importsToMarkAsBase == null) + this.importsToMarkAsBase = new ArrayList(1); + this.importsToMarkAsBase.add(qualifiedTypeName); + } + return true; + } + // Note: the "base" modifier will be provided by role org.eclipse.objectteams.otdt.ui.assist.BaseImportRewriting.ImportRewriteAdaptor + public String addImportBase(String baseName) { + return this.addImport(baseName); + } +// SH} + + +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/ListRewrite.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/ListRewrite.java new file mode 100644 index 000000000..133a3be1a --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/ListRewrite.java @@ -0,0 +1,440 @@ +/******************************************************************************* + * Copyright (c) 2004, 2009 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: + * IBM Corporation - initial API and implementation + * Technical University Berlin - extended API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.dom.rewrite; + +import java.util.Collections; +import java.util.List; + +import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.Block; +import org.eclipse.jdt.core.dom.ChildListPropertyDescriptor; +import org.eclipse.jdt.core.dom.FieldDeclaration; +import org.eclipse.jdt.core.dom.RoleTypeDeclaration; +import org.eclipse.jdt.core.dom.Statement; +import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor; +import org.eclipse.jdt.core.dom.TypeDeclaration; +import org.eclipse.jdt.internal.core.dom.rewrite.ListRewriteEvent; +import org.eclipse.jdt.internal.core.dom.rewrite.NodeInfoStore; +import org.eclipse.jdt.internal.core.dom.rewrite.RewriteEvent; +import org.eclipse.jdt.internal.core.dom.rewrite.RewriteEventStore; +import org.eclipse.jdt.internal.core.dom.rewrite.RewriteEventStore.CopySourceInfo; +import org.eclipse.text.edits.TextEditGroup; + +/** + * For describing manipulations to a child list property of an AST node. + * <p> + * This class is not intended to be subclassed. + * </p> + * @see ASTRewrite#getListRewrite(ASTNode, ChildListPropertyDescriptor) + * @since 3.0 + */ +public final class ListRewrite { + + private ASTNode parent; + private StructuralPropertyDescriptor childProperty; + private ASTRewrite rewriter; + + + /* package*/ ListRewrite(ASTRewrite rewriter, ASTNode parent, StructuralPropertyDescriptor childProperty) { + this.rewriter= rewriter; + this.parent= parent; +//{ObjectTeams: correct invalid combination TypeDeclaration/RoleTypeDeclaration: + // note: clients like ModifierCorrectionSubProcessor might need to handle + // RoleTypeDeclarations without explict knowledge. + if ( parent.getNodeType() == ASTNode.ROLE_TYPE_DECLARATION + && childProperty.getNodeClass() == TypeDeclaration.class) + { + if (childProperty == TypeDeclaration.MODIFIERS2_PROPERTY) + childProperty = RoleTypeDeclaration.MODIFIERS2_PROPERTY; + else if (childProperty == TypeDeclaration.SUPER_INTERFACE_TYPES_PROPERTY) + childProperty = RoleTypeDeclaration.SUPER_INTERFACE_TYPES_PROPERTY; + else if (childProperty == TypeDeclaration.TYPE_PARAMETERS_PROPERTY) + childProperty = RoleTypeDeclaration.TYPE_PARAMETERS_PROPERTY; + else if (childProperty == TypeDeclaration.BODY_DECLARATIONS_PROPERTY) + childProperty = RoleTypeDeclaration.BODY_DECLARATIONS_PROPERTY; + } +// SH} + this.childProperty= childProperty; + } + + private RewriteEventStore getRewriteStore() { + return this.rewriter.getRewriteEventStore(); + } + + private ListRewriteEvent getEvent() { + return getRewriteStore().getListEvent(this.parent, this.childProperty, true); + } + + /** + * Returns the parent of the list for which this list rewriter was created. + + * @return the node that contains the list for which this list rewriter was created + * @see #getLocationInParent() + * @since 3.1 + */ + public ASTNode getParent() { + return this.parent; + } + + /** + * Returns the property of the parent node for which this list rewriter was created. + * + * @return the property of the parent node for which this list rewriter was created + * @see #getParent() + * @since 3.1 + */ + public StructuralPropertyDescriptor getLocationInParent() { + return this.childProperty; + } + + /** + * Removes the given node from its parent's list property in the rewriter. + * The node must be contained in the list. + * The AST itself is not actually modified in any way; rather, the rewriter + * just records a note that this node has been removed from this list. + * + * @param node the node being removed. The node can either be an original node in this list + * or (since 3.4) a new node already inserted or used as replacement in this AST rewriter. + * @param editGroup the edit group in which to collect the corresponding + * text edits, or <code>null</code> if ungrouped + * @throws IllegalArgumentException if the node is null, or if the node is not + * part of this rewriter's AST, or if the described modification is invalid + * (not a member of this node's original list) + */ + public void remove(ASTNode node, TextEditGroup editGroup) { + if (node == null) { + throw new IllegalArgumentException(); + } + RewriteEvent event= getEvent().removeEntry(node); + if (editGroup != null) { + getRewriteStore().setEventEditGroup(event, editGroup); + } + } + + /** + * Returns the ASTRewrite instance from which this ListRewriter has been created from. + * @return the parent AST Rewriter instance. + * @since 3.1 + */ + public ASTRewrite getASTRewrite() { + return this.rewriter; + } + + + /** + * Replaces the given node from its parent's list property in the rewriter. + * The node must be contained in the list. + * The replacement node must either be brand new (not part of the original AST) + * or a placeholder node (for example, one created by + * {@link ASTRewrite#createCopyTarget(ASTNode)}, + * {@link ASTRewrite#createMoveTarget(ASTNode)}, + * or {@link ASTRewrite#createStringPlaceholder(String, int)}). The AST itself + * is not actually modified in any way; rather, the rewriter just records + * a note that this node has been replaced in this list. + * + * @param node the node being removed. The node can either be an original node in this list + * or (since 3.4) a new node already inserted or used as replacement in this AST rewriter. + * @param replacement the replacement node, or <code>null</code> if no + * replacement + * @param editGroup the edit group in which to collect the corresponding + * text edits, or <code>null</code> if ungrouped + * @throws IllegalArgumentException if the node is null, or if the node is not part + * of this rewriter's AST, or if the replacement node is not a new node (or + * placeholder), or if the described modification is otherwise invalid + * (not a member of this node's original list) + */ + public void replace(ASTNode node, ASTNode replacement, TextEditGroup editGroup) { + if (node == null) { + throw new IllegalArgumentException(); + } + RewriteEvent event= getEvent().replaceEntry(node, replacement); + if (editGroup != null) { + getRewriteStore().setEventEditGroup(event, editGroup); + } + } + + /** + * Inserts the given node into the list after the given element. + * The existing node must be in the list, either as an original or as a new + * node that has been inserted. + * The inserted node must either be brand new (not part of the original AST) + * or a placeholder node (for example, one created by + * {@link ASTRewrite#createCopyTarget(ASTNode)}, + * {@link ASTRewrite#createMoveTarget(ASTNode)}, + * or {@link ASTRewrite#createStringPlaceholder(String, int)}). The AST itself + * is not actually modified in any way; rather, the rewriter just records + * a note that this node has been inserted into the list. + * + * @param node the node to insert + * @param element the element after which the given node is to be inserted + * @param editGroup the edit group in which to collect the corresponding + * text edits, or <code>null</code> if ungrouped + * @throws IllegalArgumentException if the node or element is null, + * or if the node is not part of this rewriter's AST, or if the inserted node + * is not a new node (or placeholder), or if <code>element</code> is not a member + * of the list (original or new), or if the described modification is + * otherwise invalid + */ + public void insertAfter(ASTNode node, ASTNode element, TextEditGroup editGroup) { + if (node == null || element == null) { + throw new IllegalArgumentException(); + } + int index= getEvent().getIndex(element, ListRewriteEvent.BOTH); + if (index == -1) { + throw new IllegalArgumentException("Node does not exist"); //$NON-NLS-1$ + } + internalInsertAt(node, index + 1, true, editGroup); + } + + /** + * Inserts the given node into the list before the given element. + * The existing node must be in the list, either as an original or as a new + * node that has been inserted. + * The inserted node must either be brand new (not part of the original AST) + * or a placeholder node (for example, one created by + * {@link ASTRewrite#createCopyTarget(ASTNode)}, + * {@link ASTRewrite#createMoveTarget(ASTNode)}, + * or {@link ASTRewrite#createStringPlaceholder(String, int)}). The AST itself + * is not actually modified in any way; rather, the rewriter just records + * a note that this node has been inserted into the list. + * + * @param node the node to insert + * @param element the element before which the given node is to be inserted + * @param editGroup the edit group in which to collect the corresponding + * text edits, or <code>null</code> if ungrouped + * @throws IllegalArgumentException if the node or element is null, + * or if the node is not part of this rewriter's AST, or if the inserted node + * is not a new node (or placeholder), or if <code>element</code> is not a member + * of the list (original or new), or if the described modification is + * otherwise invalid + */ + public void insertBefore(ASTNode node, ASTNode element, TextEditGroup editGroup) { + if (node == null || element == null) { + throw new IllegalArgumentException(); + } + int index= getEvent().getIndex(element, ListRewriteEvent.BOTH); + if (index == -1) { + throw new IllegalArgumentException("Node does not exist"); //$NON-NLS-1$ + } + internalInsertAt(node, index, false, editGroup); + } + + /** + * Inserts the given node into the list at the start of the list. + * Equivalent to <code>insertAt(node, 0, editGroup)</code>. + * + * @param node the node to insert + * @param editGroup the edit group in which to collect the corresponding + * text edits, or <code>null</code> if ungrouped + * @throws IllegalArgumentException if the node is null, or if the node is not part + * of this rewriter's AST, or if the inserted node is not a new node (or + * placeholder), or if the described modification is otherwise invalid + * (not a member of this node's original list) + * @see #insertAt(ASTNode, int, TextEditGroup) + */ + public void insertFirst(ASTNode node, TextEditGroup editGroup) { + if (node == null) { + throw new IllegalArgumentException(); + } + internalInsertAt(node, 0, false, editGroup); + } + + /** + * Inserts the given node into the list at the end of the list. + * Equivalent to <code>insertAt(node, -1, editGroup)</code>. + * + * @param node the node to insert + * @param editGroup the edit group in which to collect the corresponding + * text edits, or <code>null</code> if ungrouped + * @throws IllegalArgumentException if the node is null, or if the node is not part + * of this rewriter's AST, or if the inserted node is not a new node (or + * placeholder), or if the described modification is otherwise invalid + * (not a member of this node's original list) + * @see #insertAt(ASTNode, int, TextEditGroup) + */ + public void insertLast(ASTNode node, TextEditGroup editGroup) { + if (node == null) { + throw new IllegalArgumentException(); + } + internalInsertAt(node, -1, true, editGroup); + } + + /** + * Inserts the given node into the list at the given index. + * The index corresponds to a combined list of original and new nodes; + * removed or replaced nodes are still in the combined list. + * The inserted node must either be brand new (not part of the original AST) + * or a placeholder node (for example, one created by + * {@link ASTRewrite#createCopyTarget(ASTNode)}, + * {@link ASTRewrite#createMoveTarget(ASTNode)}, + * or {@link ASTRewrite#createStringPlaceholder(String, int)}). The AST itself + * is not actually modified in any way; rather, the rewriter just records + * a note that this node has been inserted into the list. + * + * @param node the node to insert + * @param index insertion index in the combined list of original and + * inserted nodes; <code>-1</code> indicates insertion as the last element + * @param editGroup the edit group in which to collect the corresponding + * text edits, or <code>null</code> if ungrouped + * @throws IllegalArgumentException if the node is null, or if the node is not part + * of this rewriter's AST, or if the inserted node is not a new node (or + * placeholder), or if the described modification is otherwise invalid + * (not a member of this node's original list) + * @throws IndexOutOfBoundsException if the index is negative and not -1, + * or if it is larger than the size of the combined list + */ + public void insertAt(ASTNode node, int index, TextEditGroup editGroup) { + if (node == null) { + throw new IllegalArgumentException(); + } + internalInsertAt(node, index, isInsertBoundToPreviousByDefault(node), editGroup); + } + + private void internalInsertAt(ASTNode node, int index, boolean boundToPrevious, TextEditGroup editGroup) { + RewriteEvent event= getEvent().insert(node, index); + if (boundToPrevious) { + getRewriteStore().setInsertBoundToPrevious(node); + } + if (editGroup != null) { + getRewriteStore().setEventEditGroup(event, editGroup); + } + } + + + private ASTNode createTargetNode(ASTNode first, ASTNode last, boolean isMove, ASTNode replacingNode, TextEditGroup editGroup) { + if (first == null || last == null) { + throw new IllegalArgumentException(); + } + + NodeInfoStore nodeStore= this.rewriter.getNodeStore(); + ASTNode placeholder= nodeStore.newPlaceholderNode(first.getNodeType()); // revisit: could use list type + if (placeholder == null) { + throw new IllegalArgumentException("Creating a target node is not supported for nodes of type" + first.getClass().getName()); //$NON-NLS-1$ + } + + Block internalPlaceHolder= nodeStore.createCollapsePlaceholder(); + CopySourceInfo info= getRewriteStore().createRangeCopy(this.parent, this.childProperty, first, last, isMove, internalPlaceHolder, replacingNode, editGroup); + nodeStore.markAsCopyTarget(placeholder, info); + + return placeholder; + } + + /** + * Creates and returns a placeholder node for a true copy of a range of nodes of the + * current list. + * The placeholder node can either be inserted as new or used to replace an + * existing node. When the document is rewritten, a copy of the source code + * for the given node range is inserted into the output document at the position + * corresponding to the placeholder (indentation is adjusted). + * + * @param first the node that starts the range + * @param last the node that ends the range + * @return the new placeholder node + * @throws IllegalArgumentException An exception is thrown if the first or last node + * are <code>null</code>, if a node is not a child of the current list or if the first node + * is not before the last node. An <code>IllegalArgumentException</code> is + * also thrown if the copied range is overlapping with an other moved or copied range. + */ + public final ASTNode createCopyTarget(ASTNode first, ASTNode last) { + if (first == last) { + return this.rewriter.createCopyTarget(first); + } else { + return createTargetNode(first, last, false, null, null); + } + } + + /** + * Creates and returns a placeholder node for a move of a range of nodes of the + * current list. + * The placeholder node can either be inserted as new or used to replace an + * existing node. When the document is rewritten, a copy of the source code + * for the given node range is inserted into the output document at the position + * corresponding to the placeholder (indentation is adjusted). + * + * @param first the node that starts the range + * @param last the node that ends the range + * @return the new placeholder node + * @throws IllegalArgumentException An exception is thrown if the first or last node + * are <code>null</code>, if a node is not a child of the current list or if the first node + * is not before the last node. An <code>IllegalArgumentException</code> is + * also thrown if the moved range is overlapping with an other moved or copied range. + * + * @since 3.1 + */ + public final ASTNode createMoveTarget(ASTNode first, ASTNode last) { + return createMoveTarget(first, last, null, null); + } + + /** + * Creates and returns a placeholder node for a move of a range of nodes of the + * current list. The moved nodes can optionally be replaced by a specified node. + * + * The placeholder node can either be inserted as new or used to replace an + * existing node. When the document is rewritten, a copy of the source code + * for the given node range is inserted into the output document at the position + * corresponding to the placeholder (indentation is adjusted). + * + * @param first the node that starts the range + * @param last the node that ends the range + * @param replacingNode a node that is set at the location of the moved nodes + * or <code>null</code> to remove all nodes + * @param editGroup the edit group in which to collect the corresponding + * text edits fro a replace, or <code>null</code> if ungrouped + * @return the new placeholder node + * @throws IllegalArgumentException An exception is thrown if the first or + * last node are <code>null</code>, if a node is not a child of the current list or + * if the first node is not before the last node. An <code>IllegalArgumentException + * </code> is also thrown if the moved range is overlapping with an other moved + * or copied range. + * + * @since 3.1 + */ + public final ASTNode createMoveTarget(ASTNode first, ASTNode last, ASTNode replacingNode, TextEditGroup editGroup) { + if (first == last) { + replace(first, replacingNode, editGroup); + return this.rewriter.createMoveTarget(first); + } else { + return createTargetNode(first, last, true, replacingNode, editGroup); + } + } + + /* + * Heuristic to decide if a inserted node is bound to previous or the next sibling. + */ + private boolean isInsertBoundToPreviousByDefault(ASTNode node) { + return (node instanceof Statement || node instanceof FieldDeclaration); + } + + /** + * Returns the original nodes in the list property managed by this + * rewriter. The returned list is unmodifiable. + * + * @return a list of all original nodes in the list + */ + public List getOriginalList() { + List list= (List) getEvent().getOriginalValue(); + return Collections.unmodifiableList(list); + } + + /** + * Returns the nodes in the revised list property managed by this + * rewriter. The returned list is unmodifiable. + * + * @return a list of all nodes in the list taking into account + * all the described changes + */ + public List getRewrittenList() { + List list= (List) getEvent().getNewValue(); + return Collections.unmodifiableList(list); + } + +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/TargetSourceRangeComputer.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/TargetSourceRangeComputer.java new file mode 100644 index 000000000..2ed0c9f22 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/TargetSourceRangeComputer.java @@ -0,0 +1,135 @@ +/******************************************************************************* + * Copyright (c) 2005, 2009 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.dom.rewrite; + +import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.CompilationUnit; + +/** + * An object for computing adjusted source ranges for AST nodes + * that are being replaced or deleted. + * <p> + * For example, a refactoring like inline method may choose to replace + * calls to the method but leave intact any comments immediately preceding + * the calls. On the other hand, a refactoring like extract method may choose + * to extract not only the nodes for the selected code but also any + * comments preceding or following them. + * </p> + * <p> + * Clients should subclass if they need to influence the + * the source range to be affected when replacing or deleting a particular node. + * An instance of the subclass should be registered with + * {@link ASTRewrite#setTargetSourceRangeComputer(TargetSourceRangeComputer)}. + * During a call to {@link ASTRewrite#rewriteAST(org.eclipse.jface.text.IDocument, java.util.Map)}, + * the {@link #computeSourceRange(ASTNode)} method on this object will be + * used to compute the source range for a node being deleted or replaced. + * </p> + * + * @since 3.1 + */ +public class TargetSourceRangeComputer { + + /** + * Reified source range. Instances are "value" object + * (cannot be modified). + * + * @since 3.1 + */ + public static final class SourceRange { + /** + * 0-based character index, or <code>-1</code> + * if no source position information is known. + */ + private int startPosition; + + /** + * (possibly 0) length, or <code>0</code> + * if no source position information is known. + */ + private int length; + + /** + * Creates a new source range. + * + * @param startPosition the 0-based character index, or <code>-1</code> + * if no source position information is known + * @param length the (possibly 0) length, or <code>0</code> + * if no source position information is known + */ + public SourceRange(int startPosition, int length) { + this.startPosition = startPosition; + this.length = length; + } + + /** + * Returns the start position. + * + * @return the 0-based character index, or <code>-1</code> + * if no source position information is known + */ + public int getStartPosition() { + return this.startPosition; + } + + /** + * Returns the source length. + * + * @return a (possibly 0) length, or <code>0</code> + * if no source position information is known + */ + public int getLength() { + return this.length; + } + } + + /** + * Creates a new target source range computer. + */ + public TargetSourceRangeComputer() { + // do nothing + } + + /** + * Returns the target source range of the given node. Unlike + * {@link ASTNode#getStartPosition()} and {@link ASTNode#getLength()}, + * the extended source range may include comments and whitespace + * immediately before or after the normal source range for the node. + * <p> + * The returned source ranges must satisfy the following conditions: + * <dl> + * <li>no two source ranges in an AST may be overlapping</li> + * <li>a source range of a parent node must fully cover the source ranges of its children</li> + * </dl> + * </p> + * <p> + * The default implementation uses + * {@link CompilationUnit#getExtendedStartPosition(ASTNode)} + * and {@link CompilationUnit#getExtendedLength(ASTNode)} + * to compute the target source range. Clients may override or + * extend this method to expand or contract the source range of the + * given node. The resulting source range must cover at least the + * original source range of the node. + * </p> + * + * @param node the node with a known source range in the compilation unit + * being rewritten + * @return the exact source range in the compilation unit being rewritten + * that should be replaced (or deleted) + */ + public SourceRange computeSourceRange(ASTNode node) { + ASTNode root= node.getRoot(); + if (root instanceof CompilationUnit) { + CompilationUnit cu= (CompilationUnit) root; + return new SourceRange(cu.getExtendedStartPosition(node), cu.getExtendedLength(node)); + } + return new SourceRange(node.getStartPosition(), node.getLength()); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/package.html b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/package.html new file mode 100644 index 000000000..2f568acad --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/package.html @@ -0,0 +1,18 @@ +<!doctype html public "-//w3c//dtd html 4.0 transitional//en"> +<html> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <meta name="Author" content="IBM"> + <title>Package-level Javadoc</title> +</head> +<body> +The Java DOM/AST rewrite is the set of classes that are used to make changes to an existing DOM/AST tree. + +<h2> +Package Specification</h2> + +<p>This package contains the Java DOM/AST classes used to make changes to an existing DOM/AST tree. +The principal classes are {@link org.eclipse.jdt.core.dom.rewrite.ASTRewrite ASTRewrite} and +{@link org.eclipse.jdt.core.dom.rewrite.ListRewrite ListRewrite}.</p> +</body> +</html> diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/NaiveASTFlattener.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/NaiveASTFlattener.java new file mode 100644 index 000000000..587384abd --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/NaiveASTFlattener.java @@ -0,0 +1,2102 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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 + * $Id: NaiveASTFlattener.java 22567 2009-09-22 16:34:06Z stephan $ + * + * Contributors: + * IBM Corporation - initial API and implementation + * Fraunhofer FIRST - extended API and implementation + * Technical University Berlin - extended API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.core.dom; + +import java.util.Iterator; +import java.util.List; + +import org.eclipse.jdt.core.dom.*; + +/** + * Internal AST visitor for serializing an AST in a quick and dirty fashion. + * For various reasons the resulting string is not necessarily legal + * Java code; and even if it is legal Java code, it is not necessarily the string + * that corresponds to the given AST. Although useless for most purposes, it's + * fine for generating debug print strings. + * <p> + * Example usage: + * <code> + * <pre> + * NaiveASTFlattener p = new NaiveASTFlattener(); + * node.accept(p); + * String result = p.getResult(); + * </pre> + * </code> + * Call the <code>reset</code> method to clear the previous result before reusing an + * existing instance. + * </p> + * + * @since 2.0 + */ +public class NaiveASTFlattener extends ASTVisitor { + /** + * Internal synonym for {@link AST#JLS2}. Use to alleviate + * deprecation warnings. + * @deprecated + * @since 3.4 + */ + private static final int JLS2 = AST.JLS2; + + /** + * The string buffer into which the serialized representation of the AST is + * written. + */ + protected StringBuffer buffer; + + private int indent = 0; + + /** + * Creates a new AST printer. + */ + public NaiveASTFlattener() { + this.buffer = new StringBuffer(); + } + + /** + * Internal synonym for {@link ClassInstanceCreation#getName()}. Use to alleviate + * deprecation warnings. + * @deprecated + * @since 3.4 + */ + private Name getName(ClassInstanceCreation node) { + return node.getName(); + } + + /** + * Returns the string accumulated in the visit. + * + * @return the serialized + */ + public String getResult() { + return this.buffer.toString(); + } + + /** + * Internal synonym for {@link MethodDeclaration#getReturnType()}. Use to alleviate + * deprecation warnings. + * @deprecated + * @since 3.4 + */ + private Type getReturnType(MethodDeclaration node) { + return node.getReturnType(); + } + + /** + * Internal synonym for {@link TypeDeclaration#getSuperclass()}. Use to alleviate + * deprecation warnings. + * @deprecated + * @since 3.4 + */ + private Name getSuperclass(TypeDeclaration node) { + return node.getSuperclass(); + } + + /** + * Internal synonym for {@link TypeDeclarationStatement#getTypeDeclaration()}. Use to alleviate + * deprecation warnings. + * @deprecated + * @since 3.4 + */ + private TypeDeclaration getTypeDeclaration(TypeDeclarationStatement node) { + return node.getTypeDeclaration(); + } + + void printIndent() { + for (int i = 0; i < this.indent; i++) + this.buffer.append(" "); //$NON-NLS-1$ + } + + /** + * Appends the text representation of the given modifier flags, followed by a single space. + * Used for JLS2 modifiers. + * + * @param modifiers the modifier flags + */ + void printModifiers(int modifiers) { + if (Modifier.isPublic(modifiers)) { + this.buffer.append("public ");//$NON-NLS-1$ + } + if (Modifier.isProtected(modifiers)) { + this.buffer.append("protected ");//$NON-NLS-1$ + } + if (Modifier.isPrivate(modifiers)) { + this.buffer.append("private ");//$NON-NLS-1$ + } + if (Modifier.isStatic(modifiers)) { + this.buffer.append("static ");//$NON-NLS-1$ + } + if (Modifier.isAbstract(modifiers)) { + this.buffer.append("abstract ");//$NON-NLS-1$ + } + if (Modifier.isFinal(modifiers)) { + this.buffer.append("final ");//$NON-NLS-1$ + } + if (Modifier.isSynchronized(modifiers)) { + this.buffer.append("synchronized ");//$NON-NLS-1$ + } + if (Modifier.isVolatile(modifiers)) { + this.buffer.append("volatile ");//$NON-NLS-1$ + } + if (Modifier.isNative(modifiers)) { + this.buffer.append("native ");//$NON-NLS-1$ + } + if (Modifier.isStrictfp(modifiers)) { + this.buffer.append("strictfp ");//$NON-NLS-1$ + } + if (Modifier.isTransient(modifiers)) { + this.buffer.append("transient ");//$NON-NLS-1$ + } + } + + /** + * Appends the text representation of the given modifier flags, followed by a single space. + * Used for 3.0 modifiers and annotations. + * + * @param ext the list of modifier and annotation nodes + * (element type: <code>IExtendedModifiers</code>) + */ + void printModifiers(List ext) { + for (Iterator it = ext.iterator(); it.hasNext(); ) { + ASTNode p = (ASTNode) it.next(); + p.accept(this); + this.buffer.append(" ");//$NON-NLS-1$ + } + } + + /** + * Resets this printer so that it can be used again. + */ + public void reset() { + this.buffer.setLength(0); + } + + /** + * Internal synonym for {@link TypeDeclaration#superInterfaces()}. Use to alleviate + * deprecation warnings. + * @deprecated + * @since 3.4 + */ + private List superInterfaces(TypeDeclaration node) { + return node.superInterfaces(); + } + + /* + * @see ASTVisitor#visit(AnnotationTypeDeclaration) + * @since 3.1 + */ + public boolean visit(AnnotationTypeDeclaration node) { + if (node.getJavadoc() != null) { + node.getJavadoc().accept(this); + } + printIndent(); + printModifiers(node.modifiers()); + this.buffer.append("@interface ");//$NON-NLS-1$ + node.getName().accept(this); + this.buffer.append(" {");//$NON-NLS-1$ + for (Iterator it = node.bodyDeclarations().iterator(); it.hasNext(); ) { + BodyDeclaration d = (BodyDeclaration) it.next(); + d.accept(this); + } + this.buffer.append("}\n");//$NON-NLS-1$ + return false; + } + + /* + * @see ASTVisitor#visit(AnnotationTypeMemberDeclaration) + * @since 3.1 + */ + public boolean visit(AnnotationTypeMemberDeclaration node) { + if (node.getJavadoc() != null) { + node.getJavadoc().accept(this); + } + printIndent(); + printModifiers(node.modifiers()); + node.getType().accept(this); + this.buffer.append(" ");//$NON-NLS-1$ + node.getName().accept(this); + this.buffer.append("()");//$NON-NLS-1$ + if (node.getDefault() != null) { + this.buffer.append(" default ");//$NON-NLS-1$ + node.getDefault().accept(this); + } + this.buffer.append(";\n");//$NON-NLS-1$ + return false; + } + + /* + * @see ASTVisitor#visit(AnonymousClassDeclaration) + */ + public boolean visit(AnonymousClassDeclaration node) { + this.buffer.append("{\n");//$NON-NLS-1$ + this.indent++; + for (Iterator it = node.bodyDeclarations().iterator(); it.hasNext(); ) { + BodyDeclaration b = (BodyDeclaration) it.next(); + b.accept(this); + } + this.indent--; + printIndent(); + this.buffer.append("}\n");//$NON-NLS-1$ + return false; + } + + /* + * @see ASTVisitor#visit(ArrayAccess) + */ + public boolean visit(ArrayAccess node) { + node.getArray().accept(this); + this.buffer.append("[");//$NON-NLS-1$ + node.getIndex().accept(this); + this.buffer.append("]");//$NON-NLS-1$ + return false; + } + + /* + * @see ASTVisitor#visit(ArrayCreation) + */ + public boolean visit(ArrayCreation node) { + this.buffer.append("new ");//$NON-NLS-1$ + ArrayType at = node.getType(); + int dims = at.getDimensions(); + Type elementType = at.getElementType(); + elementType.accept(this); + for (Iterator it = node.dimensions().iterator(); it.hasNext(); ) { + this.buffer.append("[");//$NON-NLS-1$ + Expression e = (Expression) it.next(); + e.accept(this); + this.buffer.append("]");//$NON-NLS-1$ + dims--; + } + // add empty "[]" for each extra array dimension + for (int i= 0; i < dims; i++) { + this.buffer.append("[]");//$NON-NLS-1$ + } + if (node.getInitializer() != null) { + node.getInitializer().accept(this); + } + return false; + } + + /* + * @see ASTVisitor#visit(ArrayInitializer) + */ + public boolean visit(ArrayInitializer node) { + this.buffer.append("{");//$NON-NLS-1$ + for (Iterator it = node.expressions().iterator(); it.hasNext(); ) { + Expression e = (Expression) it.next(); + e.accept(this); + if (it.hasNext()) { + this.buffer.append(",");//$NON-NLS-1$ + } + } + this.buffer.append("}");//$NON-NLS-1$ + return false; + } + + /* + * @see ASTVisitor#visit(ArrayType) + */ + public boolean visit(ArrayType node) { + node.getComponentType().accept(this); + this.buffer.append("[]");//$NON-NLS-1$ + return false; + } + + /* + * @see ASTVisitor#visit(AssertStatement) + */ + public boolean visit(AssertStatement node) { + printIndent(); + this.buffer.append("assert ");//$NON-NLS-1$ + node.getExpression().accept(this); + if (node.getMessage() != null) { + this.buffer.append(" : ");//$NON-NLS-1$ + node.getMessage().accept(this); + } + this.buffer.append(";\n");//$NON-NLS-1$ + return false; + } + + /* + * @see ASTVisitor#visit(Assignment) + */ + public boolean visit(Assignment node) { + node.getLeftHandSide().accept(this); + this.buffer.append(node.getOperator().toString()); + node.getRightHandSide().accept(this); + return false; + } + + /* + * @see ASTVisitor#visit(Block) + */ + public boolean visit(Block node) { + this.buffer.append("{\n");//$NON-NLS-1$ + this.indent++; + for (Iterator it = node.statements().iterator(); it.hasNext(); ) { + Statement s = (Statement) it.next(); + s.accept(this); + } + this.indent--; + printIndent(); + this.buffer.append("}\n");//$NON-NLS-1$ + return false; + } + + /* + * @see ASTVisitor#visit(BlockComment) + * @since 3.0 + */ + public boolean visit(BlockComment node) { + printIndent(); + this.buffer.append("/* */");//$NON-NLS-1$ + return false; + } + + /* + * @see ASTVisitor#visit(BooleanLiteral) + */ + public boolean visit(BooleanLiteral node) { + if (node.booleanValue() == true) { + this.buffer.append("true");//$NON-NLS-1$ + } else { + this.buffer.append("false");//$NON-NLS-1$ + } + return false; + } + + /* + * @see ASTVisitor#visit(BreakStatement) + */ + public boolean visit(BreakStatement node) { + printIndent(); + this.buffer.append("break");//$NON-NLS-1$ + if (node.getLabel() != null) { + this.buffer.append(" ");//$NON-NLS-1$ + node.getLabel().accept(this); + } + this.buffer.append(";\n");//$NON-NLS-1$ + return false; + } + + /* + * @see ASTVisitor#visit(CastExpression) + */ + public boolean visit(CastExpression node) { + this.buffer.append("(");//$NON-NLS-1$ + node.getType().accept(this); + this.buffer.append(")");//$NON-NLS-1$ + node.getExpression().accept(this); + return false; + } + + /* + * @see ASTVisitor#visit(CatchClause) + */ + public boolean visit(CatchClause node) { + this.buffer.append("catch (");//$NON-NLS-1$ + node.getException().accept(this); + this.buffer.append(") ");//$NON-NLS-1$ + node.getBody().accept(this); + return false; + } + + /* + * @see ASTVisitor#visit(CharacterLiteral) + */ + public boolean visit(CharacterLiteral node) { + this.buffer.append(node.getEscapedValue()); + return false; + } + + /* + * @see ASTVisitor#visit(ClassInstanceCreation) + */ + public boolean visit(ClassInstanceCreation node) { + if (node.getExpression() != null) { + node.getExpression().accept(this); + this.buffer.append(".");//$NON-NLS-1$ + } + this.buffer.append("new ");//$NON-NLS-1$ + if (node.getAST().apiLevel() == JLS2) { + getName(node).accept(this); + } + if (node.getAST().apiLevel() >= AST.JLS3) { + if (!node.typeArguments().isEmpty()) { + this.buffer.append("<");//$NON-NLS-1$ + for (Iterator it = node.typeArguments().iterator(); it.hasNext(); ) { + Type t = (Type) it.next(); + t.accept(this); + if (it.hasNext()) { + this.buffer.append(",");//$NON-NLS-1$ + } + } + this.buffer.append(">");//$NON-NLS-1$ + } + node.getType().accept(this); + } + this.buffer.append("(");//$NON-NLS-1$ + for (Iterator it = node.arguments().iterator(); it.hasNext(); ) { + Expression e = (Expression) it.next(); + e.accept(this); + if (it.hasNext()) { + this.buffer.append(",");//$NON-NLS-1$ + } + } + this.buffer.append(")");//$NON-NLS-1$ + if (node.getAnonymousClassDeclaration() != null) { + node.getAnonymousClassDeclaration().accept(this); + } + return false; + } + + /* + * @see ASTVisitor#visit(CompilationUnit) + */ + public boolean visit(CompilationUnit node) { + if (node.getPackage() != null) { + node.getPackage().accept(this); + } + for (Iterator it = node.imports().iterator(); it.hasNext(); ) { + ImportDeclaration d = (ImportDeclaration) it.next(); + d.accept(this); + } + for (Iterator it = node.types().iterator(); it.hasNext(); ) { + AbstractTypeDeclaration d = (AbstractTypeDeclaration) it.next(); + d.accept(this); + } + return false; + } + + /* + * @see ASTVisitor#visit(ConditionalExpression) + */ + public boolean visit(ConditionalExpression node) { + node.getExpression().accept(this); + this.buffer.append(" ? ");//$NON-NLS-1$ + node.getThenExpression().accept(this); + this.buffer.append(" : ");//$NON-NLS-1$ + node.getElseExpression().accept(this); + return false; + } + + /* + * @see ASTVisitor#visit(ConstructorInvocation) + */ + public boolean visit(ConstructorInvocation node) { + printIndent(); + if (node.getAST().apiLevel() >= AST.JLS3) { + if (!node.typeArguments().isEmpty()) { + this.buffer.append("<");//$NON-NLS-1$ + for (Iterator it = node.typeArguments().iterator(); it.hasNext(); ) { + Type t = (Type) it.next(); + t.accept(this); + if (it.hasNext()) { + this.buffer.append(",");//$NON-NLS-1$ + } + } + this.buffer.append(">");//$NON-NLS-1$ + } + } + this.buffer.append("this(");//$NON-NLS-1$ + for (Iterator it = node.arguments().iterator(); it.hasNext(); ) { + Expression e = (Expression) it.next(); + e.accept(this); + if (it.hasNext()) { + this.buffer.append(",");//$NON-NLS-1$ + } + } + this.buffer.append(");\n");//$NON-NLS-1$ + return false; + } + + /* + * @see ASTVisitor#visit(ContinueStatement) + */ + public boolean visit(ContinueStatement node) { + printIndent(); + this.buffer.append("continue");//$NON-NLS-1$ + if (node.getLabel() != null) { + this.buffer.append(" ");//$NON-NLS-1$ + node.getLabel().accept(this); + } + this.buffer.append(";\n");//$NON-NLS-1$ + return false; + } + + /* + * @see ASTVisitor#visit(DoStatement) + */ + public boolean visit(DoStatement node) { + printIndent(); + this.buffer.append("do ");//$NON-NLS-1$ + node.getBody().accept(this); + this.buffer.append(" while (");//$NON-NLS-1$ + node.getExpression().accept(this); + this.buffer.append(");\n");//$NON-NLS-1$ + return false; + } + + /* + * @see ASTVisitor#visit(EmptyStatement) + */ + public boolean visit(EmptyStatement node) { + printIndent(); + this.buffer.append(";\n");//$NON-NLS-1$ + return false; + } + + /* + * @see ASTVisitor#visit(EnhancedForStatement) + * @since 3.1 + */ + public boolean visit(EnhancedForStatement node) { + printIndent(); + this.buffer.append("for (");//$NON-NLS-1$ + node.getParameter().accept(this); + this.buffer.append(" : ");//$NON-NLS-1$ + node.getExpression().accept(this); + this.buffer.append(") ");//$NON-NLS-1$ + node.getBody().accept(this); + return false; + } + + /* + * @see ASTVisitor#visit(EnumConstantDeclaration) + * @since 3.1 + */ + public boolean visit(EnumConstantDeclaration node) { + if (node.getJavadoc() != null) { + node.getJavadoc().accept(this); + } + printIndent(); + printModifiers(node.modifiers()); + node.getName().accept(this); + if (!node.arguments().isEmpty()) { + this.buffer.append("(");//$NON-NLS-1$ + for (Iterator it = node.arguments().iterator(); it.hasNext(); ) { + Expression e = (Expression) it.next(); + e.accept(this); + if (it.hasNext()) { + this.buffer.append(",");//$NON-NLS-1$ + } + } + this.buffer.append(")");//$NON-NLS-1$ + } + if (node.getAnonymousClassDeclaration() != null) { + node.getAnonymousClassDeclaration().accept(this); + } + return false; + } + + /* + * @see ASTVisitor#visit(EnumDeclaration) + * @since 3.1 + */ + public boolean visit(EnumDeclaration node) { + if (node.getJavadoc() != null) { + node.getJavadoc().accept(this); + } + printIndent(); + printModifiers(node.modifiers()); + this.buffer.append("enum ");//$NON-NLS-1$ + node.getName().accept(this); + this.buffer.append(" ");//$NON-NLS-1$ + if (!node.superInterfaceTypes().isEmpty()) { + this.buffer.append("implements ");//$NON-NLS-1$ + for (Iterator it = node.superInterfaceTypes().iterator(); it.hasNext(); ) { + Type t = (Type) it.next(); + t.accept(this); + if (it.hasNext()) { + this.buffer.append(", ");//$NON-NLS-1$ + } + } + this.buffer.append(" ");//$NON-NLS-1$ + } + this.buffer.append("{");//$NON-NLS-1$ + for (Iterator it = node.enumConstants().iterator(); it.hasNext(); ) { + EnumConstantDeclaration d = (EnumConstantDeclaration) it.next(); + d.accept(this); + // enum constant declarations do not include punctuation + if (it.hasNext()) { + // enum constant declarations are separated by commas + this.buffer.append(", ");//$NON-NLS-1$ + } + } + if (!node.bodyDeclarations().isEmpty()) { + this.buffer.append("; ");//$NON-NLS-1$ + for (Iterator it = node.bodyDeclarations().iterator(); it.hasNext(); ) { + BodyDeclaration d = (BodyDeclaration) it.next(); + d.accept(this); + // other body declarations include trailing punctuation + } + } + this.buffer.append("}\n");//$NON-NLS-1$ + return false; + } + + /* + * @see ASTVisitor#visit(ExpressionStatement) + */ + public boolean visit(ExpressionStatement node) { + printIndent(); + node.getExpression().accept(this); + this.buffer.append(";\n");//$NON-NLS-1$ + return false; + } + + /* + * @see ASTVisitor#visit(FieldAccess) + */ + public boolean visit(FieldAccess node) { + node.getExpression().accept(this); + this.buffer.append(".");//$NON-NLS-1$ + node.getName().accept(this); + return false; + } + + /* + * @see ASTVisitor#visit(FieldDeclaration) + */ + public boolean visit(FieldDeclaration node) { + if (node.getJavadoc() != null) { + node.getJavadoc().accept(this); + } + printIndent(); + if (node.getAST().apiLevel() == JLS2) { + printModifiers(node.getModifiers()); + } + if (node.getAST().apiLevel() >= AST.JLS3) { + printModifiers(node.modifiers()); + } + node.getType().accept(this); + this.buffer.append(" ");//$NON-NLS-1$ + for (Iterator it = node.fragments().iterator(); it.hasNext(); ) { + VariableDeclarationFragment f = (VariableDeclarationFragment) it.next(); + f.accept(this); + if (it.hasNext()) { + this.buffer.append(", ");//$NON-NLS-1$ + } + } + this.buffer.append(";\n");//$NON-NLS-1$ + return false; + } + + /* + * @see ASTVisitor#visit(ForStatement) + */ + public boolean visit(ForStatement node) { + printIndent(); + this.buffer.append("for (");//$NON-NLS-1$ + for (Iterator it = node.initializers().iterator(); it.hasNext(); ) { + Expression e = (Expression) it.next(); + e.accept(this); + if (it.hasNext()) this.buffer.append(", ");//$NON-NLS-1$ + } + this.buffer.append("; ");//$NON-NLS-1$ + if (node.getExpression() != null) { + node.getExpression().accept(this); + } + this.buffer.append("; ");//$NON-NLS-1$ + for (Iterator it = node.updaters().iterator(); it.hasNext(); ) { + Expression e = (Expression) it.next(); + e.accept(this); + if (it.hasNext()) this.buffer.append(", ");//$NON-NLS-1$ + } + this.buffer.append(") ");//$NON-NLS-1$ + node.getBody().accept(this); + return false; + } + + /* + * @see ASTVisitor#visit(IfStatement) + */ + public boolean visit(IfStatement node) { + printIndent(); + this.buffer.append("if (");//$NON-NLS-1$ + node.getExpression().accept(this); + this.buffer.append(") ");//$NON-NLS-1$ + node.getThenStatement().accept(this); + if (node.getElseStatement() != null) { + this.buffer.append(" else ");//$NON-NLS-1$ + node.getElseStatement().accept(this); + } + return false; + } + + /* + * @see ASTVisitor#visit(ImportDeclaration) + */ + public boolean visit(ImportDeclaration node) { + printIndent(); + this.buffer.append("import ");//$NON-NLS-1$ +//{ObjectTeams: base import + if (node.getAST().apiLevel() >= AST.JLS3) { + if (node.isBase()) { + this.buffer.append("base ");//$NON-NLS-1$ + } + } +// SH} + if (node.getAST().apiLevel() >= AST.JLS3) { + if (node.isStatic()) { + this.buffer.append("static ");//$NON-NLS-1$ + } + } + node.getName().accept(this); + if (node.isOnDemand()) { + this.buffer.append(".*");//$NON-NLS-1$ + } + this.buffer.append(";\n");//$NON-NLS-1$ + return false; + } + + /* + * @see ASTVisitor#visit(InfixExpression) + */ + public boolean visit(InfixExpression node) { + node.getLeftOperand().accept(this); + this.buffer.append(' '); // for cases like x= i - -1; or x= i++ + ++i; + this.buffer.append(node.getOperator().toString()); + this.buffer.append(' '); + node.getRightOperand().accept(this); + final List extendedOperands = node.extendedOperands(); + if (extendedOperands.size() != 0) { + this.buffer.append(' '); + for (Iterator it = extendedOperands.iterator(); it.hasNext(); ) { + this.buffer.append(node.getOperator().toString()).append(' '); + Expression e = (Expression) it.next(); + e.accept(this); + } + } + return false; + } + + /* + * @see ASTVisitor#visit(Initializer) + */ + public boolean visit(Initializer node) { + if (node.getJavadoc() != null) { + node.getJavadoc().accept(this); + } + if (node.getAST().apiLevel() == JLS2) { + printModifiers(node.getModifiers()); + } + if (node.getAST().apiLevel() >= AST.JLS3) { + printModifiers(node.modifiers()); + } + node.getBody().accept(this); + return false; + } + + /* + * @see ASTVisitor#visit(InstanceofExpression) + */ + public boolean visit(InstanceofExpression node) { + node.getLeftOperand().accept(this); + this.buffer.append(" instanceof ");//$NON-NLS-1$ + node.getRightOperand().accept(this); + return false; + } + + /* + * @see ASTVisitor#visit(Javadoc) + */ + public boolean visit(Javadoc node) { + printIndent(); + this.buffer.append("/** ");//$NON-NLS-1$ + for (Iterator it = node.tags().iterator(); it.hasNext(); ) { + ASTNode e = (ASTNode) it.next(); + e.accept(this); + } + this.buffer.append("\n */\n");//$NON-NLS-1$ + return false; + } + + /* + * @see ASTVisitor#visit(LabeledStatement) + */ + public boolean visit(LabeledStatement node) { + printIndent(); + node.getLabel().accept(this); + this.buffer.append(": ");//$NON-NLS-1$ + node.getBody().accept(this); + return false; + } + + /* + * @see ASTVisitor#visit(LineComment) + * @since 3.0 + */ + public boolean visit(LineComment node) { + this.buffer.append("//\n");//$NON-NLS-1$ + return false; + } + + /* + * @see ASTVisitor#visit(MarkerAnnotation) + * @since 3.1 + */ + public boolean visit(MarkerAnnotation node) { + this.buffer.append("@");//$NON-NLS-1$ + node.getTypeName().accept(this); + return false; + } + + /* + * @see ASTVisitor#visit(MemberRef) + * @since 3.0 + */ + public boolean visit(MemberRef node) { + if (node.getQualifier() != null) { + node.getQualifier().accept(this); + } + this.buffer.append("#");//$NON-NLS-1$ + node.getName().accept(this); + return false; + } + + /* + * @see ASTVisitor#visit(MemberValuePair) + * @since 3.1 + */ + public boolean visit(MemberValuePair node) { + node.getName().accept(this); + this.buffer.append("=");//$NON-NLS-1$ + node.getValue().accept(this); + return false; + } + + /* + * @see ASTVisitor#visit(MethodDeclaration) + */ + public boolean visit(MethodDeclaration node) { + if (node.getJavadoc() != null) { + node.getJavadoc().accept(this); + } + printIndent(); + if (node.getAST().apiLevel() == JLS2) { + printModifiers(node.getModifiers()); + } + if (node.getAST().apiLevel() >= AST.JLS3) { + printModifiers(node.modifiers()); + if (!node.typeParameters().isEmpty()) { + this.buffer.append("<");//$NON-NLS-1$ + for (Iterator it = node.typeParameters().iterator(); it.hasNext(); ) { + TypeParameter t = (TypeParameter) it.next(); + t.accept(this); + if (it.hasNext()) { + this.buffer.append(",");//$NON-NLS-1$ + } + } + this.buffer.append(">");//$NON-NLS-1$ + } + } + if (!node.isConstructor()) { + if (node.getAST().apiLevel() == JLS2) { + getReturnType(node).accept(this); + } else { + if (node.getReturnType2() != null) { + node.getReturnType2().accept(this); + } else { + // methods really ought to have a return type + this.buffer.append("void");//$NON-NLS-1$ + } + } + this.buffer.append(" ");//$NON-NLS-1$ + } + node.getName().accept(this); + this.buffer.append("(");//$NON-NLS-1$ + for (Iterator it = node.parameters().iterator(); it.hasNext(); ) { + SingleVariableDeclaration v = (SingleVariableDeclaration) it.next(); + v.accept(this); + if (it.hasNext()) { + this.buffer.append(",");//$NON-NLS-1$ + } + } + this.buffer.append(")");//$NON-NLS-1$ + for (int i = 0; i < node.getExtraDimensions(); i++) { + this.buffer.append("[]"); //$NON-NLS-1$ + } + if (!node.thrownExceptions().isEmpty()) { + this.buffer.append(" throws ");//$NON-NLS-1$ + for (Iterator it = node.thrownExceptions().iterator(); it.hasNext(); ) { + Name n = (Name) it.next(); + n.accept(this); + if (it.hasNext()) { + this.buffer.append(", ");//$NON-NLS-1$ + } + } + this.buffer.append(" ");//$NON-NLS-1$ + } + if (node.getBody() == null) { + this.buffer.append(";\n");//$NON-NLS-1$ + } else { + node.getBody().accept(this); + } + return false; + } + + /* + * @see ASTVisitor#visit(MethodInvocation) + */ + public boolean visit(MethodInvocation node) { + if (node.getExpression() != null) { + node.getExpression().accept(this); + this.buffer.append(".");//$NON-NLS-1$ + } + if (node.getAST().apiLevel() >= AST.JLS3) { + if (!node.typeArguments().isEmpty()) { + this.buffer.append("<");//$NON-NLS-1$ + for (Iterator it = node.typeArguments().iterator(); it.hasNext(); ) { + Type t = (Type) it.next(); + t.accept(this); + if (it.hasNext()) { + this.buffer.append(",");//$NON-NLS-1$ + } + } + this.buffer.append(">");//$NON-NLS-1$ + } + } + node.getName().accept(this); + this.buffer.append("(");//$NON-NLS-1$ + for (Iterator it = node.arguments().iterator(); it.hasNext(); ) { + Expression e = (Expression) it.next(); + e.accept(this); + if (it.hasNext()) { + this.buffer.append(",");//$NON-NLS-1$ + } + } + this.buffer.append(")");//$NON-NLS-1$ + return false; + } + + /* + * @see ASTVisitor#visit(MethodRef) + * @since 3.0 + */ + public boolean visit(MethodRef node) { + if (node.getQualifier() != null) { + node.getQualifier().accept(this); + } + this.buffer.append("#");//$NON-NLS-1$ + node.getName().accept(this); + this.buffer.append("(");//$NON-NLS-1$ + for (Iterator it = node.parameters().iterator(); it.hasNext(); ) { + MethodRefParameter e = (MethodRefParameter) it.next(); + e.accept(this); + if (it.hasNext()) { + this.buffer.append(",");//$NON-NLS-1$ + } + } + this.buffer.append(")");//$NON-NLS-1$ + return false; + } + + /* + * @see ASTVisitor#visit(MethodRefParameter) + * @since 3.0 + */ + public boolean visit(MethodRefParameter node) { + node.getType().accept(this); + if (node.getAST().apiLevel() >= AST.JLS3) { + if (node.isVarargs()) { + this.buffer.append("...");//$NON-NLS-1$ + } + } + if (node.getName() != null) { + this.buffer.append(" ");//$NON-NLS-1$ + node.getName().accept(this); + } + return false; + } + + /* + * @see ASTVisitor#visit(Modifier) + * @since 3.1 + */ + public boolean visit(Modifier node) { + this.buffer.append(node.getKeyword().toString()); + return false; + } + + /* + * @see ASTVisitor#visit(NormalAnnotation) + * @since 3.1 + */ + public boolean visit(NormalAnnotation node) { + this.buffer.append("@");//$NON-NLS-1$ + node.getTypeName().accept(this); + this.buffer.append("(");//$NON-NLS-1$ + for (Iterator it = node.values().iterator(); it.hasNext(); ) { + MemberValuePair p = (MemberValuePair) it.next(); + p.accept(this); + if (it.hasNext()) { + this.buffer.append(",");//$NON-NLS-1$ + } + } + this.buffer.append(")");//$NON-NLS-1$ + return false; + } + + /* + * @see ASTVisitor#visit(NullLiteral) + */ + public boolean visit(NullLiteral node) { + this.buffer.append("null");//$NON-NLS-1$ + return false; + } + + /* + * @see ASTVisitor#visit(NumberLiteral) + */ + public boolean visit(NumberLiteral node) { + this.buffer.append(node.getToken()); + return false; + } + + /* + * @see ASTVisitor#visit(PackageDeclaration) + */ + public boolean visit(PackageDeclaration node) { + if (node.getAST().apiLevel() >= AST.JLS3) { + if (node.getJavadoc() != null) { + node.getJavadoc().accept(this); + } + for (Iterator it = node.annotations().iterator(); it.hasNext(); ) { + Annotation p = (Annotation) it.next(); + p.accept(this); + this.buffer.append(" ");//$NON-NLS-1$ + } + } + printIndent(); + this.buffer.append("package ");//$NON-NLS-1$ + node.getName().accept(this); + this.buffer.append(";\n");//$NON-NLS-1$ + return false; + } + + /* + * @see ASTVisitor#visit(ParameterizedType) + * @since 3.1 + */ + public boolean visit(ParameterizedType node) { + node.getType().accept(this); + this.buffer.append("<");//$NON-NLS-1$ + for (Iterator it = node.typeArguments().iterator(); it.hasNext(); ) { + Type t = (Type) it.next(); + t.accept(this); + if (it.hasNext()) { + this.buffer.append(",");//$NON-NLS-1$ + } + } + this.buffer.append(">");//$NON-NLS-1$ + return false; + } + + /* + * @see ASTVisitor#visit(ParenthesizedExpression) + */ + public boolean visit(ParenthesizedExpression node) { + this.buffer.append("(");//$NON-NLS-1$ + node.getExpression().accept(this); + this.buffer.append(")");//$NON-NLS-1$ + return false; + } + + /* + * @see ASTVisitor#visit(PostfixExpression) + */ + public boolean visit(PostfixExpression node) { + node.getOperand().accept(this); + this.buffer.append(node.getOperator().toString()); + return false; + } + + /* + * @see ASTVisitor#visit(PrefixExpression) + */ + public boolean visit(PrefixExpression node) { + this.buffer.append(node.getOperator().toString()); + node.getOperand().accept(this); + return false; + } + + /* + * @see ASTVisitor#visit(PrimitiveType) + */ + public boolean visit(PrimitiveType node) { + this.buffer.append(node.getPrimitiveTypeCode().toString()); + return false; + } + + /* + * @see ASTVisitor#visit(QualifiedName) + */ + public boolean visit(QualifiedName node) { + node.getQualifier().accept(this); + this.buffer.append(".");//$NON-NLS-1$ + node.getName().accept(this); + return false; + } + + /* + * @see ASTVisitor#visit(QualifiedType) + * @since 3.1 + */ + public boolean visit(QualifiedType node) { + node.getQualifier().accept(this); + this.buffer.append(".");//$NON-NLS-1$ + node.getName().accept(this); + return false; + } + + /* + * @see ASTVisitor#visit(ReturnStatement) + */ + public boolean visit(ReturnStatement node) { + printIndent(); + this.buffer.append("return");//$NON-NLS-1$ + if (node.getExpression() != null) { + this.buffer.append(" ");//$NON-NLS-1$ + node.getExpression().accept(this); + } + this.buffer.append(";\n");//$NON-NLS-1$ + return false; + } + + /* + * @see ASTVisitor#visit(SimpleName) + */ + public boolean visit(SimpleName node) { + this.buffer.append(node.getIdentifier()); + return false; + } + + /* + * @see ASTVisitor#visit(SimpleType) + */ + public boolean visit(SimpleType node) { + return true; + } + + /* + * @see ASTVisitor#visit(SingleMemberAnnotation) + * @since 3.1 + */ + public boolean visit(SingleMemberAnnotation node) { + this.buffer.append("@");//$NON-NLS-1$ + node.getTypeName().accept(this); + this.buffer.append("(");//$NON-NLS-1$ + node.getValue().accept(this); + this.buffer.append(")");//$NON-NLS-1$ + return false; + } + + /* + * @see ASTVisitor#visit(SingleVariableDeclaration) + */ + public boolean visit(SingleVariableDeclaration node) { + printIndent(); + if (node.getAST().apiLevel() == JLS2) { + printModifiers(node.getModifiers()); + } + if (node.getAST().apiLevel() >= AST.JLS3) { + printModifiers(node.modifiers()); + } + node.getType().accept(this); + if (node.getAST().apiLevel() >= AST.JLS3) { + if (node.isVarargs()) { + this.buffer.append("...");//$NON-NLS-1$ + } + } + this.buffer.append(" ");//$NON-NLS-1$ + node.getName().accept(this); + for (int i = 0; i < node.getExtraDimensions(); i++) { + this.buffer.append("[]"); //$NON-NLS-1$ + } + if (node.getInitializer() != null) { + this.buffer.append("=");//$NON-NLS-1$ + node.getInitializer().accept(this); + } + return false; + } + + /* + * @see ASTVisitor#visit(StringLiteral) + */ + public boolean visit(StringLiteral node) { + this.buffer.append(node.getEscapedValue()); + return false; + } + + /* + * @see ASTVisitor#visit(SuperConstructorInvocation) + */ + public boolean visit(SuperConstructorInvocation node) { + printIndent(); + if (node.getExpression() != null) { + node.getExpression().accept(this); + this.buffer.append(".");//$NON-NLS-1$ + } + if (node.getAST().apiLevel() >= AST.JLS3) { + if (!node.typeArguments().isEmpty()) { + this.buffer.append("<");//$NON-NLS-1$ + for (Iterator it = node.typeArguments().iterator(); it.hasNext(); ) { + Type t = (Type) it.next(); + t.accept(this); + if (it.hasNext()) { + this.buffer.append(",");//$NON-NLS-1$ + } + } + this.buffer.append(">");//$NON-NLS-1$ + } + } + this.buffer.append("super(");//$NON-NLS-1$ + for (Iterator it = node.arguments().iterator(); it.hasNext(); ) { + Expression e = (Expression) it.next(); + e.accept(this); + if (it.hasNext()) { + this.buffer.append(",");//$NON-NLS-1$ + } + } + this.buffer.append(");\n");//$NON-NLS-1$ + return false; + } + + /* + * @see ASTVisitor#visit(SuperFieldAccess) + */ + public boolean visit(SuperFieldAccess node) { + if (node.getQualifier() != null) { + node.getQualifier().accept(this); + this.buffer.append(".");//$NON-NLS-1$ + } + this.buffer.append("super.");//$NON-NLS-1$ + node.getName().accept(this); + return false; + } + + /* + * @see ASTVisitor#visit(SuperMethodInvocation) + */ + public boolean visit(SuperMethodInvocation node) { + if (node.getQualifier() != null) { + node.getQualifier().accept(this); + this.buffer.append(".");//$NON-NLS-1$ + } + this.buffer.append("super.");//$NON-NLS-1$ + if (node.getAST().apiLevel() >= AST.JLS3) { + if (!node.typeArguments().isEmpty()) { + this.buffer.append("<");//$NON-NLS-1$ + for (Iterator it = node.typeArguments().iterator(); it.hasNext(); ) { + Type t = (Type) it.next(); + t.accept(this); + if (it.hasNext()) { + this.buffer.append(",");//$NON-NLS-1$ + } + } + this.buffer.append(">");//$NON-NLS-1$ + } + } + node.getName().accept(this); + this.buffer.append("(");//$NON-NLS-1$ + for (Iterator it = node.arguments().iterator(); it.hasNext(); ) { + Expression e = (Expression) it.next(); + e.accept(this); + if (it.hasNext()) { + this.buffer.append(",");//$NON-NLS-1$ + } + } + this.buffer.append(")");//$NON-NLS-1$ + return false; + } + + /* + * @see ASTVisitor#visit(SwitchCase) + */ + public boolean visit(SwitchCase node) { + if (node.isDefault()) { + this.buffer.append("default :\n");//$NON-NLS-1$ + } else { + this.buffer.append("case ");//$NON-NLS-1$ + node.getExpression().accept(this); + this.buffer.append(":\n");//$NON-NLS-1$ + } + this.indent++; //decremented in visit(SwitchStatement) + return false; + } + + /* + * @see ASTVisitor#visit(SwitchStatement) + */ + public boolean visit(SwitchStatement node) { + this.buffer.append("switch (");//$NON-NLS-1$ + node.getExpression().accept(this); + this.buffer.append(") ");//$NON-NLS-1$ + this.buffer.append("{\n");//$NON-NLS-1$ + this.indent++; + for (Iterator it = node.statements().iterator(); it.hasNext(); ) { + Statement s = (Statement) it.next(); + s.accept(this); + this.indent--; // incremented in visit(SwitchCase) + } + this.indent--; + printIndent(); + this.buffer.append("}\n");//$NON-NLS-1$ + return false; + } + + /* + * @see ASTVisitor#visit(SynchronizedStatement) + */ + public boolean visit(SynchronizedStatement node) { + this.buffer.append("synchronized (");//$NON-NLS-1$ + node.getExpression().accept(this); + this.buffer.append(") ");//$NON-NLS-1$ + node.getBody().accept(this); + return false; + } + + /* + * @see ASTVisitor#visit(TagElement) + * @since 3.0 + */ + public boolean visit(TagElement node) { + if (node.isNested()) { + // nested tags are always enclosed in braces + this.buffer.append("{");//$NON-NLS-1$ + } else { + // top-level tags always begin on a new line + this.buffer.append("\n * ");//$NON-NLS-1$ + } + boolean previousRequiresWhiteSpace = false; + if (node.getTagName() != null) { + this.buffer.append(node.getTagName()); + previousRequiresWhiteSpace = true; + } + boolean previousRequiresNewLine = false; + for (Iterator it = node.fragments().iterator(); it.hasNext(); ) { + ASTNode e = (ASTNode) it.next(); + // assume text elements include necessary leading and trailing whitespace + // but Name, MemberRef, MethodRef, and nested TagElement do not include white space + boolean currentIncludesWhiteSpace = (e instanceof TextElement); + if (previousRequiresNewLine && currentIncludesWhiteSpace) { + this.buffer.append("\n * ");//$NON-NLS-1$ + } + previousRequiresNewLine = currentIncludesWhiteSpace; + // add space if required to separate + if (previousRequiresWhiteSpace && !currentIncludesWhiteSpace) { + this.buffer.append(" "); //$NON-NLS-1$ + } + e.accept(this); + previousRequiresWhiteSpace = !currentIncludesWhiteSpace && !(e instanceof TagElement); + } + if (node.isNested()) { + this.buffer.append("}");//$NON-NLS-1$ + } + return false; + } + + /* + * @see ASTVisitor#visit(TextElement) + * @since 3.0 + */ + public boolean visit(TextElement node) { + this.buffer.append(node.getText()); + return false; + } + + /* + * @see ASTVisitor#visit(ThisExpression) + */ + public boolean visit(ThisExpression node) { + if (node.getQualifier() != null) { + node.getQualifier().accept(this); + this.buffer.append(".");//$NON-NLS-1$ + } + this.buffer.append("this");//$NON-NLS-1$ + return false; + } + + /* + * @see ASTVisitor#visit(ThrowStatement) + */ + public boolean visit(ThrowStatement node) { + printIndent(); + this.buffer.append("throw ");//$NON-NLS-1$ + node.getExpression().accept(this); + this.buffer.append(";\n");//$NON-NLS-1$ + return false; + } + + /* + * @see ASTVisitor#visit(TryStatement) + */ + public boolean visit(TryStatement node) { + printIndent(); + this.buffer.append("try ");//$NON-NLS-1$ + node.getBody().accept(this); + this.buffer.append(" ");//$NON-NLS-1$ + for (Iterator it = node.catchClauses().iterator(); it.hasNext(); ) { + CatchClause cc = (CatchClause) it.next(); + cc.accept(this); + } + if (node.getFinally() != null) { + this.buffer.append(" finally ");//$NON-NLS-1$ + node.getFinally().accept(this); + } + return false; + } + + /* + * @see ASTVisitor#visit(TypeDeclaration) + */ + public boolean visit(TypeDeclaration node) { + if (node.getJavadoc() != null) { + node.getJavadoc().accept(this); + } + if (node.getAST().apiLevel() == JLS2) { + printModifiers(node.getModifiers()); + } + if (node.getAST().apiLevel() >= AST.JLS3) { + printModifiers(node.modifiers()); + } + this.buffer.append(node.isInterface() ? "interface " : "class ");//$NON-NLS-2$//$NON-NLS-1$ + node.getName().accept(this); + if (node.getAST().apiLevel() >= AST.JLS3) { + if (!node.typeParameters().isEmpty()) { + this.buffer.append("<");//$NON-NLS-1$ + for (Iterator it = node.typeParameters().iterator(); it.hasNext(); ) { + TypeParameter t = (TypeParameter) it.next(); + t.accept(this); + if (it.hasNext()) { + this.buffer.append(",");//$NON-NLS-1$ + } + } + this.buffer.append(">");//$NON-NLS-1$ + } + } + this.buffer.append(" ");//$NON-NLS-1$ + if (node.getAST().apiLevel() == JLS2) { + if (getSuperclass(node) != null) { + this.buffer.append("extends ");//$NON-NLS-1$ + getSuperclass(node).accept(this); + this.buffer.append(" ");//$NON-NLS-1$ + } + if (!superInterfaces(node).isEmpty()) { + this.buffer.append(node.isInterface() ? "extends " : "implements ");//$NON-NLS-2$//$NON-NLS-1$ + for (Iterator it = superInterfaces(node).iterator(); it.hasNext(); ) { + Name n = (Name) it.next(); + n.accept(this); + if (it.hasNext()) { + this.buffer.append(", ");//$NON-NLS-1$ + } + } + this.buffer.append(" ");//$NON-NLS-1$ + } + } + if (node.getAST().apiLevel() >= AST.JLS3) { + if (node.getSuperclassType() != null) { + this.buffer.append("extends ");//$NON-NLS-1$ + node.getSuperclassType().accept(this); + this.buffer.append(" ");//$NON-NLS-1$ + } + if (!node.superInterfaceTypes().isEmpty()) { + this.buffer.append(node.isInterface() ? "extends " : "implements ");//$NON-NLS-2$//$NON-NLS-1$ + for (Iterator it = node.superInterfaceTypes().iterator(); it.hasNext(); ) { + Type t = (Type) it.next(); + t.accept(this); + if (it.hasNext()) { + this.buffer.append(", ");//$NON-NLS-1$ + } + } + this.buffer.append(" ");//$NON-NLS-1$ + } + } + this.buffer.append("{\n");//$NON-NLS-1$ + this.indent++; + for (Iterator it = node.bodyDeclarations().iterator(); it.hasNext(); ) { + BodyDeclaration d = (BodyDeclaration) it.next(); + d.accept(this); + } + this.indent--; + printIndent(); + this.buffer.append("}\n");//$NON-NLS-1$ + return false; + } + + /* + * @see ASTVisitor#visit(TypeDeclarationStatement) + */ + public boolean visit(TypeDeclarationStatement node) { + if (node.getAST().apiLevel() == JLS2) { + getTypeDeclaration(node).accept(this); + } + if (node.getAST().apiLevel() >= AST.JLS3) { + node.getDeclaration().accept(this); + } + return false; + } + + /* + * @see ASTVisitor#visit(TypeLiteral) + */ + public boolean visit(TypeLiteral node) { + node.getType().accept(this); + this.buffer.append(".class");//$NON-NLS-1$ + return false; + } + + /* + * @see ASTVisitor#visit(TypeParameter) + * @since 3.1 + */ + public boolean visit(TypeParameter node) { + node.getName().accept(this); + if (!node.typeBounds().isEmpty()) { +//{ObjectTeams: "base" bound? + if (node.hasBaseBound()) + this.buffer.append(" base "); //$NON-NLS-1$ + else +// SH} + this.buffer.append(" extends ");//$NON-NLS-1$ + for (Iterator it = node.typeBounds().iterator(); it.hasNext(); ) { + Type t = (Type) it.next(); + t.accept(this); + if (it.hasNext()) { + this.buffer.append(" & ");//$NON-NLS-1$ + } + } + } + return false; + } + + /* + * @see ASTVisitor#visit(VariableDeclarationExpression) + */ + public boolean visit(VariableDeclarationExpression node) { + if (node.getAST().apiLevel() == JLS2) { + printModifiers(node.getModifiers()); + } + if (node.getAST().apiLevel() >= AST.JLS3) { + printModifiers(node.modifiers()); + } + node.getType().accept(this); + this.buffer.append(" ");//$NON-NLS-1$ + for (Iterator it = node.fragments().iterator(); it.hasNext(); ) { + VariableDeclarationFragment f = (VariableDeclarationFragment) it.next(); + f.accept(this); + if (it.hasNext()) { + this.buffer.append(", ");//$NON-NLS-1$ + } + } + return false; + } + + /* + * @see ASTVisitor#visit(VariableDeclarationFragment) + */ + public boolean visit(VariableDeclarationFragment node) { + node.getName().accept(this); + for (int i = 0; i < node.getExtraDimensions(); i++) { + this.buffer.append("[]");//$NON-NLS-1$ + } + if (node.getInitializer() != null) { + this.buffer.append("=");//$NON-NLS-1$ + node.getInitializer().accept(this); + } + return false; + } + + /* + * @see ASTVisitor#visit(VariableDeclarationStatement) + */ + public boolean visit(VariableDeclarationStatement node) { + printIndent(); + if (node.getAST().apiLevel() == JLS2) { + printModifiers(node.getModifiers()); + } + if (node.getAST().apiLevel() >= AST.JLS3) { + printModifiers(node.modifiers()); + } + node.getType().accept(this); + this.buffer.append(" ");//$NON-NLS-1$ + for (Iterator it = node.fragments().iterator(); it.hasNext(); ) { + VariableDeclarationFragment f = (VariableDeclarationFragment) it.next(); + f.accept(this); + if (it.hasNext()) { + this.buffer.append(", ");//$NON-NLS-1$ + } + } + this.buffer.append(";\n");//$NON-NLS-1$ + return false; + } + + /* + * @see ASTVisitor#visit(WhileStatement) + */ + public boolean visit(WhileStatement node) { + printIndent(); + this.buffer.append("while (");//$NON-NLS-1$ + node.getExpression().accept(this); + this.buffer.append(") ");//$NON-NLS-1$ + node.getBody().accept(this); + return false; + } + + /* + * @see ASTVisitor#visit(WildcardType) + * @since 3.1 + */ + public boolean visit(WildcardType node) { + this.buffer.append("?");//$NON-NLS-1$ + Type bound = node.getBound(); + if (bound != null) { + if (node.isUpperBound()) { + this.buffer.append(" extends ");//$NON-NLS-1$ + } else { + this.buffer.append(" super ");//$NON-NLS-1$ + } + bound.accept(this); + } + return false; + } + +//{ObjectTeams: visit methods for OT-specific types + /* + * @see ASTVisitor#visit(MethodSpec) + */ + @SuppressWarnings("nls") + public boolean visit(MethodSpec node) + { + if (node.getAST().apiLevel() == JLS2) + throw new UnsupportedOperationException("JLS2 no longer supported for OT/J"); + if (node.hasSignature()) + { + if (!node.typeParameters().isEmpty()) { + this.buffer.append("<");//$NON-NLS-1$ + for (Iterator it = node.typeParameters().iterator(); it.hasNext(); ) { + TypeParameter t = (TypeParameter) it.next(); + t.accept(this); + if (it.hasNext()) { + this.buffer.append(",");//$NON-NLS-1$ + } + } + this.buffer.append("> ");//$NON-NLS-1$ + } + node.getReturnType2().accept(this); + if (node.hasCovariantReturn()) + buffer.append('+'); + buffer.append(" "); + } + node.getName().accept(this); + if (node.hasSignature()) + { + buffer.append("("); + for (Iterator iter = node.parameters().iterator(); iter.hasNext(); ) + { + SingleVariableDeclaration var = (SingleVariableDeclaration) iter.next(); + var.accept(this); + if (iter.hasNext()) + { + buffer.append(","); + } + } + buffer.append(")"); + } + return false; + } + + /* + * @see ASTVisitor#visit(FieldAccessSpec) + */ + @SuppressWarnings("nls") + public boolean visit(FieldAccessSpec node) + { + if (node.hasSignature()) + { + node.getFieldType().accept(this); // TODO(SH): must this be updated similar to returnType2? + buffer.append(" "); + } + node.getName().accept(this); + return false; + } + + /* + * @see ASTVisitor#visit(CallinMappingDeclaration) + */ + @SuppressWarnings("nls") + public boolean visit(CallinMappingDeclaration node) + { + if (node.getJavadoc() != null) + { + node.getJavadoc().accept(this); + } + + if ((node.getRoleMappingElement() != null) + && (node.getBaseMappingElements() != null)) + { + node.getRoleMappingElement().accept(this); + buffer.append(" "); + buffer.append(CallinMappingDeclaration.CALLIN); + buffer.append(" "); + if (node.getCallinModifier() != 0) + { + node.callinModifier().accept(this); + buffer.append(" "); + } + + for (Iterator iter = node.getBaseMappingElements().iterator(); iter.hasNext();) + { + MethodSpec rightMethodSpec = (MethodSpec) iter.next(); + rightMethodSpec.accept(this); + if (iter.hasNext()) + { + buffer.append(", "); + } + } + } + else + { + node.setFlags(ASTNode.MALFORMED); + } + + GuardPredicateDeclaration guard = node.getGuardPredicate(); + if (guard != null) { + if (guard.isBase()) + buffer.append(" base when("); + else + buffer.append(" when("); + guard.getExpression().accept(this); + buffer.append(")"); + } + + if (!node.getParameterMappings().isEmpty()) + { + buffer.append(" with\n{\n"); + for (Iterator iter = node.getParameterMappings().iterator(); iter.hasNext(); ) + { + buffer.append("\t"); + ParameterMapping parameterMapping = (ParameterMapping) iter.next(); + parameterMapping.accept(this); + if (iter.hasNext()) + { + buffer.append(",\n"); + } + } + buffer.append("\n}"); + } + else + { + buffer.append(";"); + } + + return false; + } + + /* + * @see ASTVisitor#visit(CalloutMappingDeclaration) + */ + @SuppressWarnings("nls") + public boolean visit(CalloutMappingDeclaration node) + { + if (node.getJavadoc() != null) + { + node.getJavadoc().accept(this); + } + printModifiers(node.modifiers()); + if ((node.getRoleMappingElement() != null) + && (node.getBaseMappingElement() != null)) + { + node.getRoleMappingElement().accept(this); + buffer.append(" "); + if (node.isCalloutOverride()) + { + buffer.append(CalloutMappingDeclaration.CALLOUT_OVERRIDE); + } + else + { + buffer.append(CalloutMappingDeclaration.CALLOUT); + } + buffer.append(" "); + switch (node.bindingOperator().getBindingModifier()) { + case Modifier.OT_SET_CALLOUT : buffer.append("set "); break; + case Modifier.OT_GET_CALLOUT : buffer.append("get "); break; + } + node.getBaseMappingElement().accept(this); + } + else + { + node.setFlags(ASTNode.MALFORMED); + } + + if (!node.getParameterMappings().isEmpty()) + { + buffer.append(" with\n{\n"); + for (Iterator iter = node.getParameterMappings().iterator(); iter.hasNext(); ) + { + buffer.append("\t"); + ParameterMapping parameterMapping = (ParameterMapping) iter.next(); + parameterMapping.accept(this); + if (iter.hasNext()) + { + buffer.append(",\n"); + } + } + buffer.append("\n}"); + } + else + { + buffer.append(";"); + } + return false; + } + + /* + * @see ASTVisitor#visit(LiftingType) + */ + @SuppressWarnings("nls") + public boolean visit(LiftingType node) + { + node.getBaseType().accept(this); + buffer.append(" as "); + node.getRoleType().accept(this); + return false; + } + + /* + * @see ASTVisitor#visit(TypeAnchor) + */ + public boolean visit(TypeAnchor node) + { + buffer.append('@'); + node.getPath().accept(this); + return false; + } + + /* + * @see ASTVisitor#visit(WithinStatement) + */ + @SuppressWarnings("nls") + public boolean visit(WithinStatement node) + { + buffer.append("within("); + node.getTeamExpression().accept(this); + buffer.append(") "); + node.getBody().accept(this); + return false; + } + + /* + * @see ASTVisitor#visit(TSuperMessageSend) + */ + @SuppressWarnings("nls") + public boolean visit(TSuperMessageSend node) + { + ASTNode qualifier = node.getQualifier(); + if (qualifier != null) { + qualifier.accept(this); + buffer.append('.'); + } + + buffer.append("tsuper."); + node.getName().accept(this); + buffer.append("("); + for (Iterator iter = node.getArguments().iterator(); iter.hasNext(); ) + { + Expression var = (Expression)iter.next(); + var.accept(this); + if (iter.hasNext()) + { + buffer.append(", "); + } + } + buffer.append(")"); + return false; + } + + /* + * @see ASTVisitor#visit(TSuperConstructorInvocation) + */ + @SuppressWarnings("nls") + public boolean visit(TSuperConstructorInvocation node) + { + buffer.append("tsuper"); + buffer.append("("); + for (Iterator iter = node.getArguments().iterator(); iter.hasNext(); ) + { + Expression var = (Expression)iter.next(); + var.accept(this); + if (iter.hasNext()) + { + buffer.append(", "); + } + } + buffer.append(")"); + return false; + } + + + + /* + * @see ASTVisitor#visit(BaseCallMessageSend) + */ + @SuppressWarnings("nls") + public boolean visit(BaseCallMessageSend node) + { + buffer.append("base."); + buffer.append(node.getName()); + buffer.append("("); + for (Iterator iter = node.getArguments().iterator(); iter.hasNext(); ) + { + Expression var = (Expression)iter.next(); + var.accept(this); + if (iter.hasNext()) + { + buffer.append(", "); + } + } + buffer.append(")"); + return false; + } + + /* + * @see ASTVisitor#visit(BaseConstructorMessageSend) + */ + @SuppressWarnings("nls") + public boolean visit(BaseConstructorInvocation node) + { + buffer.append("base("); + for (Iterator iter = node.getArguments().iterator(); iter.hasNext(); ) + { + Expression var = (Expression)iter.next(); + var.accept(this); + if (iter.hasNext()) + { + buffer.append(", "); + } + } + buffer.append(");"); + return false; + } + + /* + * @see ASTVisitor#visit(ParameterMapping) + */ + @SuppressWarnings("nls") + public boolean visit(ParameterMapping node) + { + if (node.getExpression() != null) + { + if (node.getDirection().equals("->")) + { + node.getExpression().accept(this); + buffer.append(node.getDirection()); + buffer.append(node.getIdentifier()); + } + if (node.getDirection().equals("<-")) + { + buffer.append(node.getIdentifier()); + buffer.append(node.getDirection()); + node.getExpression().accept(this); + } + } + return false; + } + + /* + * @see ASTVisitor#visit(RoleTypeDeclaration) + */ + public boolean visit(RoleTypeDeclaration node) { + // COPY&PASTE from visit(TypeDeclaration) plus "playedBy Base" + if (node.getJavadoc() != null) { + node.getJavadoc().accept(this); + } + if (node.getAST().apiLevel() == JLS2) { + printModifiers(node.getModifiers()); + } + if (node.getAST().apiLevel() >= AST.JLS3) { + printModifiers(node.modifiers()); + } + this.buffer.append(node.isInterface() ? "interface " : "class ");//$NON-NLS-2$//$NON-NLS-1$ + node.getName().accept(this); + if (node.getAST().apiLevel() >= AST.JLS3) { + if (!node.typeParameters().isEmpty()) { + this.buffer.append("<");//$NON-NLS-1$ + for (Iterator it = node.typeParameters().iterator(); it.hasNext(); ) { + TypeParameter t = (TypeParameter) it.next(); + t.accept(this); + if (it.hasNext()) { + this.buffer.append(",");//$NON-NLS-1$ + } + } + this.buffer.append(">");//$NON-NLS-1$ + } + } + this.buffer.append(" ");//$NON-NLS-1$ + if (node.getAST().apiLevel() == JLS2) { + if (this.getSuperclass(node) != null) { + this.buffer.append("extends ");//$NON-NLS-1$ + this.getSuperclass(node).accept(this); + this.buffer.append(" ");//$NON-NLS-1$ + } + if (!this.superInterfaces(node).isEmpty()) { + this.buffer.append(node.isInterface() ? "extends " : "implements ");//$NON-NLS-2$//$NON-NLS-1$ + for (Iterator it = this.superInterfaces(node).iterator(); it.hasNext(); ) { + Name n = (Name) it.next(); + n.accept(this); + if (it.hasNext()) { + this.buffer.append(", ");//$NON-NLS-1$ + } + } + this.buffer.append(" ");//$NON-NLS-1$ + } + } + if (node.getAST().apiLevel() >= AST.JLS3) { + if (node.getSuperclassType() != null) { + this.buffer.append("extends ");//$NON-NLS-1$ + node.getSuperclassType().accept(this); + this.buffer.append(" ");//$NON-NLS-1$ + } + if (!node.superInterfaceTypes().isEmpty()) { + this.buffer.append(node.isInterface() ? "extends " : "implements ");//$NON-NLS-2$//$NON-NLS-1$ + for (Iterator it = node.superInterfaceTypes().iterator(); it.hasNext(); ) { + Type t = (Type) it.next(); + t.accept(this); + if (it.hasNext()) { + this.buffer.append(", ");//$NON-NLS-1$ + } + } + this.buffer.append(" ");//$NON-NLS-1$ + } + if (node.getBaseClassType() != null) { + this.buffer.append("playedBy ");//$NON-NLS-1$ + node.getBaseClassType().accept(this); + this.buffer.append(" ");//$NON-NLS-1$ + } + } + this.buffer.append("{\n");//$NON-NLS-1$ + this.indent++; + for (Iterator it = node.bodyDeclarations().iterator(); it.hasNext(); ) { + BodyDeclaration d = (BodyDeclaration) it.next(); + d.accept(this); + } + this.indent--; + printIndent(); + this.buffer.append("}\n");//$NON-NLS-1$ + return false; + } +//gbr} + + +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteAnalyzer.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteAnalyzer.java new file mode 100644 index 000000000..de5259b82 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteAnalyzer.java @@ -0,0 +1,4363 @@ +/******************************************************************************* + * Copyright (c) 2000, 2010 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 + * $Id: ASTRewriteAnalyzer.java 23264 2010-01-15 23:44:16Z stephan $ + * + * Contributors: + * IBM Corporation - initial API and implementation + * Fraunhofer FIRST - extended API and implementation + * Technical University Berlin - extended API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.core.dom.rewrite; + +import java.util.ArrayList; +import java.util.IdentityHashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Stack; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jdt.core.dom.*; +import org.eclipse.jdt.core.dom.Modifier.ModifierKeyword; +import org.eclipse.jdt.core.dom.rewrite.TargetSourceRangeComputer; +import org.eclipse.jdt.core.dom.rewrite.TargetSourceRangeComputer.SourceRange; +import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants; +import org.eclipse.jdt.core.formatter.IndentManipulation; +import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; +import org.eclipse.jdt.internal.compiler.parser.RecoveryScanner; +import org.eclipse.jdt.internal.compiler.parser.RecoveryScannerData; +import org.eclipse.jdt.internal.compiler.parser.Scanner; +import org.eclipse.jdt.internal.compiler.parser.ScannerHelper; +import org.eclipse.jdt.internal.compiler.parser.TerminalTokens; +import org.eclipse.jdt.internal.compiler.util.Util; +import org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteFormatter.BlockContext; +import org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteFormatter.NodeMarker; +import org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteFormatter.Prefix; +import org.eclipse.jdt.internal.core.dom.rewrite.NodeInfoStore.CopyPlaceholderData; +import org.eclipse.jdt.internal.core.dom.rewrite.NodeInfoStore.StringPlaceholderData; +import org.eclipse.jdt.internal.core.dom.rewrite.RewriteEventStore.CopySourceInfo; +import org.eclipse.text.edits.CopySourceEdit; +import org.eclipse.text.edits.CopyTargetEdit; +import org.eclipse.text.edits.DeleteEdit; +import org.eclipse.text.edits.InsertEdit; +import org.eclipse.text.edits.MoveSourceEdit; +import org.eclipse.text.edits.MoveTargetEdit; +import org.eclipse.text.edits.RangeMarker; +import org.eclipse.text.edits.ReplaceEdit; +import org.eclipse.text.edits.TextEdit; +import org.eclipse.text.edits.TextEditGroup; + + +/** + * Infrastructure to support code modifications. Existing code must stay untouched, new code + * added with correct formatting, moved code left with the user's formatting / comments. + * Idea: + * - Get the AST for existing code + * - Describe changes + * - This visitor analyzes the changes or annotations and generates text edits + * (text manipulation API) that describe the required code changes. + */ +public final class ASTRewriteAnalyzer extends ASTVisitor { + + /** + * Internal synonym for deprecated constant AST.JLS2 + * to alleviate deprecated warnings. + * @deprecated + */ + /*package*/ static final int JLS2_INTERNAL = AST.JLS2; + + TextEdit currentEdit; + final RewriteEventStore eventStore; // used from inner classes + + private TokenScanner tokenScanner; // shared scanner + + private final Map sourceCopyInfoToEdit; + private final Stack sourceCopyEndNodes; + + private final char[] content; + private final LineInformation lineInfo; + private final ASTRewriteFormatter formatter; + private final NodeInfoStore nodeInfos; + private final TargetSourceRangeComputer extendedSourceRangeComputer; + private final LineCommentEndOffsets lineCommentEndOffsets; + + private int beforeRequiredSpaceIndex = -1; + + Map options; + + private RecoveryScannerData recoveryScannerData; + + /** + * Constructor for ASTRewriteAnalyzer. + * <p>The given options cannot be null.</p> + * + * @param content the content of the compilation unit to rewrite. + * @param lineInfo line information for the content of the compilation unit to rewrite. + * @param rootEdit the edit to add all generated edits to + * @param eventStore the event store containing the description of changes + * @param nodeInfos annotations to nodes, such as if a node is a string placeholder or a copy target + * @param comments list of comments of the compilation unit to rewrite (elements of type <code>Comment</code>) or <code>null</code>. + * @param options the current jdt.core options (formatting/compliance) + * @param extendedSourceRangeComputer the source range computer to use + * @param recoveryScannerData internal data used by {@link RecoveryScanner} + */ + public ASTRewriteAnalyzer( + char[] content, + LineInformation lineInfo, + String lineDelim, + TextEdit rootEdit, + RewriteEventStore eventStore, + NodeInfoStore nodeInfos, + List comments, + Map options, + TargetSourceRangeComputer extendedSourceRangeComputer, + RecoveryScannerData recoveryScannerData) { + this.eventStore= eventStore; + this.content= content; + this.lineInfo= lineInfo; + this.nodeInfos= nodeInfos; + this.tokenScanner= null; + this.currentEdit= rootEdit; + this.sourceCopyInfoToEdit= new IdentityHashMap(); + this.sourceCopyEndNodes= new Stack(); + + this.formatter= new ASTRewriteFormatter(nodeInfos, eventStore, options, lineDelim); + + this.extendedSourceRangeComputer = extendedSourceRangeComputer; + this.lineCommentEndOffsets= new LineCommentEndOffsets(comments); + + this.options = options; + + this.recoveryScannerData = recoveryScannerData; + } + + final TokenScanner getScanner() { + if (this.tokenScanner == null) { + CompilerOptions compilerOptions = new CompilerOptions(this.options); + Scanner scanner; + if (this.recoveryScannerData == null) { + scanner = + new Scanner( + true,/*tokenizeComments*/ + false,/*tokenizeWhiteSpace*/ + false,/*checkNonExternalizedStringLiterals*/ + compilerOptions.sourceLevel, + compilerOptions.complianceLevel, + null/*taskTags*/, + null/*taskPriorities*/, + true/*taskCaseSensitive*/); + } else { + scanner = + new RecoveryScanner( + false,/*tokenizeWhiteSpace*/ + false,/*checkNonExternalizedStringLiterals*/ + compilerOptions.sourceLevel, + compilerOptions.complianceLevel, + null/*taskTags*/, + null/*taskPriorities*/, + true/*taskCaseSensitive*/, + this.recoveryScannerData); + } + scanner.setSource(this.content); + this.tokenScanner= new TokenScanner(scanner); + } + return this.tokenScanner; + } + + final char[] getContent() { + return this.content; + } + + final LineInformation getLineInformation() { + return this.lineInfo; + } + + /** + * Returns the extended source range for a node. + * + * @return an extended source range (never null) + * @since 3.1 + */ + final SourceRange getExtendedRange(ASTNode node) { + if (this.eventStore.isRangeCopyPlaceholder(node)) { + return new SourceRange(node.getStartPosition(), node.getLength()); + } + return this.extendedSourceRangeComputer.computeSourceRange(node); + } + + final int getExtendedOffset(ASTNode node) { + return getExtendedRange(node).getStartPosition(); + } + + final int getExtendedEnd(ASTNode node) { + TargetSourceRangeComputer.SourceRange range= getExtendedRange(node); + return range.getStartPosition() + range.getLength(); + } + + final TextEdit getCopySourceEdit(CopySourceInfo info) { + TextEdit edit= (TextEdit) this.sourceCopyInfoToEdit.get(info); + if (edit == null) { + SourceRange range= getExtendedRange(info.getNode()); + int start= range.getStartPosition(); + int end= start + range.getLength(); + if (info.isMove) { + MoveSourceEdit moveSourceEdit= new MoveSourceEdit(start, end - start); + moveSourceEdit.setTargetEdit(new MoveTargetEdit(0)); + edit= moveSourceEdit; + } else { + CopySourceEdit copySourceEdit= new CopySourceEdit(start, end - start); + copySourceEdit.setTargetEdit(new CopyTargetEdit(0)); + edit= copySourceEdit; + } + this.sourceCopyInfoToEdit.put(info, edit); + } + return edit; + } + + private final int getChangeKind(ASTNode node, StructuralPropertyDescriptor property) { + RewriteEvent event= getEvent(node, property); + if (event != null) { + return event.getChangeKind(); + } + return RewriteEvent.UNCHANGED; + } + + private final boolean hasChildrenChanges(ASTNode node) { + return this.eventStore.hasChangedProperties(node); + } + + private final boolean isChanged(ASTNode node, StructuralPropertyDescriptor property) { + RewriteEvent event= getEvent(node, property); + if (event != null) { + return event.getChangeKind() != RewriteEvent.UNCHANGED; + } + return false; + } + + private final boolean isCollapsed(ASTNode node) { + return this.nodeInfos.isCollapsed(node); + } + + final boolean isInsertBoundToPrevious(ASTNode node) { + return this.eventStore.isInsertBoundToPrevious(node); + } + + private final TextEditGroup getEditGroup(ASTNode parent, StructuralPropertyDescriptor property) { + RewriteEvent event= getEvent(parent, property); + if (event != null) { + return getEditGroup(event); + } + return null; + } + + final RewriteEvent getEvent(ASTNode parent, StructuralPropertyDescriptor property) { + return this.eventStore.getEvent(parent, property); + } + + final TextEditGroup getEditGroup(RewriteEvent change) { + return this.eventStore.getEventEditGroup(change); + } + + private final Object getOriginalValue(ASTNode parent, StructuralPropertyDescriptor property) { + return this.eventStore.getOriginalValue(parent, property); + } + + private final Object getNewValue(ASTNode parent, StructuralPropertyDescriptor property) { + return this.eventStore.getNewValue(parent, property); + } + + final void addEdit(TextEdit edit) { + this.currentEdit.addChild(edit); + } + + final String getLineDelimiter() { + return this.formatter.getLineDelimiter(); + } + + final String createIndentString(int indent) { + return this.formatter.createIndentString(indent); + } + + final private String getIndentOfLine(int pos) { + int line= getLineInformation().getLineOfOffset(pos); + if (line >= 0) { + char[] cont= getContent(); + int lineStart= getLineInformation().getLineOffset(line); + int i= lineStart; + while (i < cont.length && IndentManipulation.isIndentChar(this.content[i])) { + i++; + } + return new String(cont, lineStart, i - lineStart); + } + return Util.EMPTY_STRING; + } + + + final String getIndentAtOffset(int pos) { + return this.formatter.getIndentString(getIndentOfLine(pos)); + } + + final void doTextInsert(int offset, String insertString, TextEditGroup editGroup) { + if (insertString.length() > 0) { + // bug fix for 95839: problem with inserting at the end of a line comment + if (this.lineCommentEndOffsets.isEndOfLineComment(offset, this.content)) { + if (!insertString.startsWith(getLineDelimiter())) { + TextEdit edit= new InsertEdit(offset, getLineDelimiter()); // add a line delimiter + addEdit(edit); + if (editGroup != null) { + addEditGroup(editGroup, edit); + } + } + this.lineCommentEndOffsets.remove(offset); // only one line delimiter per line comment required + } + TextEdit edit= new InsertEdit(offset, insertString); + addEdit(edit); + if (editGroup != null) { + addEditGroup(editGroup, edit); + } + } + } + + final void addEditGroup(TextEditGroup editGroup, TextEdit edit) { + editGroup.addTextEdit(edit); + } + + final TextEdit doTextRemove(int offset, int len, TextEditGroup editGroup) { + if (len == 0) { + return null; + } + TextEdit edit= new DeleteEdit(offset, len); + addEdit(edit); + if (editGroup != null) { + addEditGroup(editGroup, edit); + } + return edit; + } + + final void doTextRemoveAndVisit(int offset, int len, ASTNode node, TextEditGroup editGroup) { + TextEdit edit= doTextRemove(offset, len, editGroup); + if (edit != null) { + this.currentEdit= edit; + voidVisit(node); + this.currentEdit= edit.getParent(); + } else { + voidVisit(node); + } + } + + final int doVisit(ASTNode node) { + node.accept(this); + return getExtendedEnd(node); + } + + private final int doVisit(ASTNode parent, StructuralPropertyDescriptor property, int offset) { + Object node= getOriginalValue(parent, property); + if (property.isChildProperty() && node != null) { + return doVisit((ASTNode) node); + } else if (property.isChildListProperty()) { + return doVisitList((List) node, offset); + } + return offset; + } + + private int doVisitList(List list, int offset) { + int endPos= offset; + for (Iterator iter= list.iterator(); iter.hasNext();) { + ASTNode curr= ((ASTNode) iter.next()); + endPos= doVisit(curr); + } + return endPos; + } + + final void voidVisit(ASTNode node) { + node.accept(this); + } + + private final void voidVisit(ASTNode parent, StructuralPropertyDescriptor property) { + Object node= getOriginalValue(parent, property); + if (property.isChildProperty() && node != null) { + voidVisit((ASTNode) node); + } else if (property.isChildListProperty()) { + voidVisitList((List) node); + } + } + + private void voidVisitList(List list) { + for (Iterator iter= list.iterator(); iter.hasNext();) { + doVisit(((ASTNode) iter.next())); + } + } + + private final boolean doVisitUnchangedChildren(ASTNode parent) { + List properties= parent.structuralPropertiesForType(); + for (int i= 0; i < properties.size(); i++) { + voidVisit(parent, (StructuralPropertyDescriptor) properties.get(i)); + } + return false; + } + + + private final void doTextReplace(int offset, int len, String insertString, TextEditGroup editGroup) { + if (len > 0 || insertString.length() > 0) { + TextEdit edit= new ReplaceEdit(offset, len, insertString); + addEdit(edit); + if (editGroup != null) { + addEditGroup(editGroup, edit); + } + } + } + + private final TextEdit doTextCopy(TextEdit sourceEdit, int destOffset, int sourceIndentLevel, String destIndentString, TextEditGroup editGroup) { + TextEdit targetEdit; + SourceModifier modifier= new SourceModifier(sourceIndentLevel, destIndentString, this.formatter.getTabWidth(), this.formatter.getIndentWidth()); + + if (sourceEdit instanceof MoveSourceEdit) { + MoveSourceEdit moveEdit= (MoveSourceEdit) sourceEdit; + moveEdit.setSourceModifier(modifier); + + targetEdit= new MoveTargetEdit(destOffset, moveEdit); + addEdit(targetEdit); + } else { + CopySourceEdit copyEdit= (CopySourceEdit) sourceEdit; + copyEdit.setSourceModifier(modifier); + + targetEdit= new CopyTargetEdit(destOffset, copyEdit); + addEdit(targetEdit); + } + + if (editGroup != null) { + addEditGroup(editGroup, sourceEdit); + addEditGroup(editGroup, targetEdit); + } + return targetEdit; + + } + + private void changeNotSupported(ASTNode node) { + Assert.isTrue(false, "Change not supported in " + node.getClass().getName()); //$NON-NLS-1$ + } + + + class ListRewriter { + protected String contantSeparator; + protected int startPos; + + protected RewriteEvent[] list; + + protected final ASTNode getOriginalNode(int index) { + return (ASTNode) this.list[index].getOriginalValue(); + } + + protected final ASTNode getNewNode(int index) { + return (ASTNode) this.list[index].getNewValue(); + } + + protected String getSeparatorString(int nodeIndex) { + return this.contantSeparator; + } + + protected int getInitialIndent() { + return getIndent(this.startPos); + } + + protected int getNodeIndent(int nodeIndex) { + ASTNode node= getOriginalNode(nodeIndex); + if (node == null) { + for (int i= nodeIndex - 1; i>= 0; i--) { + ASTNode curr= getOriginalNode(i); + if (curr != null) { + return getIndent(curr.getStartPosition()); + } + } + return getInitialIndent(); + } + return getIndent(node.getStartPosition()); + } + + protected int getStartOfNextNode(int nextIndex, int defaultPos) { + for (int i= nextIndex; i < this.list.length; i++) { + RewriteEvent elem= this.list[i]; + if (elem.getChangeKind() != RewriteEvent.INSERTED) { + ASTNode node= (ASTNode) elem.getOriginalValue(); + return getExtendedOffset(node); + } + } + return defaultPos; + } + + protected int getEndOfNode(ASTNode node) { + return getExtendedEnd(node); + } + + public final int rewriteList(ASTNode parent, StructuralPropertyDescriptor property, int offset, String keyword, String separator) { + this.contantSeparator= separator; + return rewriteList(parent, property, offset, keyword); + } + + private boolean insertAfterSeparator(ASTNode node) { + return !isInsertBoundToPrevious(node); + } + + protected boolean mustRemoveSeparator(int originalOffset, int nodeIndex) { + return true; + } + + public final int rewriteList(ASTNode parent, StructuralPropertyDescriptor property, int offset, String keyword) { + this.startPos= offset; + this.list= getEvent(parent, property).getChildren(); + + int total= this.list.length; + if (total == 0) { + return this.startPos; + } + + int currPos= -1; + + int lastNonInsert= -1; + int lastNonDelete= -1; + + for (int i= 0; i < total; i++) { + int currMark= this.list[i].getChangeKind(); + + if (currMark != RewriteEvent.INSERTED) { + lastNonInsert= i; + if (currPos == -1) { + ASTNode elem= (ASTNode) this.list[i].getOriginalValue(); + currPos= getExtendedOffset(elem); + } + } + if (currMark != RewriteEvent.REMOVED) { + lastNonDelete= i; + } + } + + if (currPos == -1) { // only inserts + if (keyword.length() > 0) { // creating a new list -> insert keyword first (e.g. " throws ") + TextEditGroup editGroup= getEditGroup(this.list[0]); // first node is insert + doTextInsert(offset, keyword, editGroup); + } + currPos= offset; + } + if (lastNonDelete == -1) { // all removed, set back to start so the keyword is removed as well + currPos= offset; + } + + int prevEnd= currPos; + int prevMark= RewriteEvent.UNCHANGED; + + final int NONE= 0, NEW= 1, EXISTING= 2; + int separatorState= NEW; + + for (int i= 0; i < total; i++) { + RewriteEvent currEvent= this.list[i]; + int currMark= currEvent.getChangeKind(); + int nextIndex= i + 1; + + if (currMark == RewriteEvent.INSERTED) { + TextEditGroup editGroup= getEditGroup(currEvent); + ASTNode node= (ASTNode) currEvent.getNewValue(); + + if (separatorState == NONE) { // element after last existing element (but not first) + doTextInsert(currPos, getSeparatorString(i - 1), editGroup); // insert separator + separatorState= NEW; + } + if (separatorState == NEW || insertAfterSeparator(node)) { + if (separatorState == EXISTING) { + updateIndent(prevMark, currPos, i, editGroup); + } + + doTextInsert(currPos, node, getNodeIndent(i), true, editGroup); // insert node + + separatorState= NEW; + if (i != lastNonDelete) { + if (this.list[nextIndex].getChangeKind() != RewriteEvent.INSERTED) { + doTextInsert(currPos, getSeparatorString(i), editGroup); // insert separator + } else { + separatorState= NONE; + } + } + } else { // EXISTING && insert before separator + doTextInsert(prevEnd, getSeparatorString(i - 1), editGroup); + doTextInsert(prevEnd, node, getNodeIndent(i), true, editGroup); + } + } else if (currMark == RewriteEvent.REMOVED) { + ASTNode node= (ASTNode) currEvent.getOriginalValue(); + TextEditGroup editGroup= getEditGroup(currEvent); + int currEnd= getEndOfNode(node); + if (i > lastNonDelete && separatorState == EXISTING) { + // is last, remove previous separator: split delete to allow range copies + doTextRemove(prevEnd, currPos - prevEnd, editGroup); // remove separator + doTextRemoveAndVisit(currPos, currEnd - currPos, node, editGroup); // remove node + currPos= currEnd; + prevEnd= currEnd; + } else { + if (i < lastNonDelete) { + updateIndent(prevMark, currPos, i, editGroup); + } + + // remove element and next separator + int end= getStartOfNextNode(nextIndex, currEnd); // start of next + doTextRemoveAndVisit(currPos, currEnd - currPos, node, getEditGroup(currEvent)); // remove node + if (mustRemoveSeparator(currPos, i)) { + doTextRemove(currEnd, end - currEnd, editGroup); // remove separator + } + currPos= end; + prevEnd= currEnd; + separatorState= NEW; + } + } else { // replaced or unchanged + if (currMark == RewriteEvent.REPLACED) { + ASTNode node= (ASTNode) currEvent.getOriginalValue(); + int currEnd= getEndOfNode(node); + + TextEditGroup editGroup= getEditGroup(currEvent); + ASTNode changed= (ASTNode) currEvent.getNewValue(); + + updateIndent(prevMark, currPos, i, editGroup); + + doTextRemoveAndVisit(currPos, currEnd - currPos, node, editGroup); + doTextInsert(currPos, changed, getNodeIndent(i), true, editGroup); + + prevEnd= currEnd; + } else { // is unchanged + ASTNode node= (ASTNode) currEvent.getOriginalValue(); + voidVisit(node); + } + if (i == lastNonInsert) { // last node or next nodes are all inserts + separatorState= NONE; + if (currMark == RewriteEvent.UNCHANGED) { + ASTNode node= (ASTNode) currEvent.getOriginalValue(); + prevEnd= getEndOfNode(node); + } + currPos= prevEnd; + } else if (this.list[nextIndex].getChangeKind() != RewriteEvent.UNCHANGED) { + // no updates needed while nodes are unchanged + if (currMark == RewriteEvent.UNCHANGED) { + ASTNode node= (ASTNode) currEvent.getOriginalValue(); + prevEnd= getEndOfNode(node); + } + currPos= getStartOfNextNode(nextIndex, prevEnd); // start of next + separatorState= EXISTING; + } + } + + prevMark = currMark; + } + return currPos; + } + + protected void updateIndent(int prevMark, int originalOffset, int nodeIndex, TextEditGroup editGroup) { + // Do nothing. + } + } + + private int rewriteRequiredNode(ASTNode parent, StructuralPropertyDescriptor property) { + RewriteEvent event= getEvent(parent, property); + if (event != null && event.getChangeKind() == RewriteEvent.REPLACED) { + ASTNode node= (ASTNode) event.getOriginalValue(); + TextEditGroup editGroup= getEditGroup(event); + SourceRange range= getExtendedRange(node); + int offset= range.getStartPosition(); + int length= range.getLength(); +//{ObjectTeams: missing modifier? + boolean isMissingModifier = node instanceof Modifier + && ((Modifier)node).getKeyword() == ModifierKeyword.MISSING_KEYWORD; + if (isMissingModifier) + doTextInsert(offset, " ", editGroup); // separate insertion from preceding text. //$NON-NLS-1$ +// SH} + doTextRemoveAndVisit(offset, length, node, editGroup); + doTextInsert(offset, (ASTNode) event.getNewValue(), getIndent(offset), true, editGroup); + return offset + length; + } + return doVisit(parent, property, 0); + } + + private int rewriteNode(ASTNode parent, StructuralPropertyDescriptor property, int offset, Prefix prefix) { + RewriteEvent event= getEvent(parent, property); + if (event != null) { + switch (event.getChangeKind()) { + case RewriteEvent.INSERTED: { + ASTNode node= (ASTNode) event.getNewValue(); + TextEditGroup editGroup= getEditGroup(event); + int indent= getIndent(offset); + doTextInsert(offset, prefix.getPrefix(indent), editGroup); + doTextInsert(offset, node, indent, true, editGroup); + return offset; + } + case RewriteEvent.REMOVED: { + ASTNode node= (ASTNode) event.getOriginalValue(); + TextEditGroup editGroup= getEditGroup(event); + + // if there is a prefix, remove the prefix as well + int nodeEnd; + int len; + if (offset == 0) { + SourceRange range= getExtendedRange(node); + offset= range.getStartPosition(); + len= range.getLength(); + nodeEnd= offset+len; + } else { + nodeEnd= getExtendedEnd(node); + len= nodeEnd-offset; + } + doTextRemoveAndVisit(offset, len, node, editGroup); + return nodeEnd; + } + case RewriteEvent.REPLACED: { + ASTNode node= (ASTNode) event.getOriginalValue(); + TextEditGroup editGroup= getEditGroup(event); + SourceRange range= getExtendedRange(node); + int nodeOffset= range.getStartPosition(); + int nodeLen= range.getLength(); + doTextRemoveAndVisit(nodeOffset, nodeLen, node, editGroup); + doTextInsert(nodeOffset, (ASTNode) event.getNewValue(), getIndent(offset), true, editGroup); + return nodeOffset + nodeLen; + } + } + } + return doVisit(parent, property, offset); + } + + private int rewriteJavadoc(ASTNode node, StructuralPropertyDescriptor property) { + int pos= rewriteNode(node, property, node.getStartPosition(), ASTRewriteFormatter.NONE); + int changeKind= getChangeKind(node, property); + if (changeKind == RewriteEvent.INSERTED) { + String indent= getLineDelimiter() + getIndentAtOffset(pos); + doTextInsert(pos, indent, getEditGroup(node, property)); + } else if (changeKind == RewriteEvent.REMOVED) { + try { + getScanner().readNext(pos, false); + doTextRemove(pos, getScanner().getCurrentStartOffset() - pos, getEditGroup(node, property)); + pos= getScanner().getCurrentStartOffset(); + } catch (CoreException e) { + handleException(e); + } + } + return pos; + } + + + /* + * endpos can be -1 -> use the end pos of the body + */ + private int rewriteBodyNode(ASTNode parent, StructuralPropertyDescriptor property, int offset, int endPos, int indent, BlockContext context) { + RewriteEvent event= getEvent(parent, property); + if (event != null) { + switch (event.getChangeKind()) { + case RewriteEvent.INSERTED: { + ASTNode node= (ASTNode) event.getNewValue(); + TextEditGroup editGroup= getEditGroup(event); + + String[] strings= context.getPrefixAndSuffix(indent, node, this.eventStore); + + doTextInsert(offset, strings[0], editGroup); + doTextInsert(offset, node, indent, true, editGroup); + doTextInsert(offset, strings[1], editGroup); + return offset; + } + case RewriteEvent.REMOVED: { + ASTNode node= (ASTNode) event.getOriginalValue(); + if (endPos == -1) { + endPos= getExtendedEnd(node); + } + + TextEditGroup editGroup= getEditGroup(event); + // if there is a prefix, remove the prefix as well + int len= endPos - offset; + doTextRemoveAndVisit(offset, len, node, editGroup); + return endPos; + } + case RewriteEvent.REPLACED: { + ASTNode node= (ASTNode) event.getOriginalValue(); + if (endPos == -1) { + endPos= getExtendedEnd(node); + } + TextEditGroup editGroup= getEditGroup(event); + int nodeLen= endPos - offset; + + ASTNode replacingNode= (ASTNode) event.getNewValue(); + String[] strings= context.getPrefixAndSuffix(indent, replacingNode, this.eventStore); + doTextRemoveAndVisit(offset, nodeLen, node, editGroup); + + String prefix= strings[0]; + doTextInsert(offset, prefix, editGroup); + String lineInPrefix= getCurrentLine(prefix, prefix.length()); + if (prefix.length() != lineInPrefix.length()) { + // prefix contains a new line: update the indent to the one used in the prefix + indent= this.formatter.computeIndentUnits(lineInPrefix); + } + doTextInsert(offset, replacingNode, indent, true, editGroup); + doTextInsert(offset, strings[1], editGroup); + return endPos; + } + } + } + int pos= doVisit(parent, property, offset); + if (endPos != -1) { + return endPos; + } + return pos; + } + + private int rewriteOptionalQualifier(ASTNode parent, StructuralPropertyDescriptor property, int startPos) { + RewriteEvent event= getEvent(parent, property); + if (event != null) { + switch (event.getChangeKind()) { + case RewriteEvent.INSERTED: { + ASTNode node= (ASTNode) event.getNewValue(); + TextEditGroup editGroup= getEditGroup(event); + doTextInsert(startPos, node, getIndent(startPos), true, editGroup); + doTextInsert(startPos, ".", editGroup); //$NON-NLS-1$ + return startPos; + } + case RewriteEvent.REMOVED: { + try { + ASTNode node= (ASTNode) event.getOriginalValue(); + TextEditGroup editGroup= getEditGroup(event); + int dotEnd= getScanner().getTokenEndOffset(TerminalTokens.TokenNameDOT, node.getStartPosition() + node.getLength()); + doTextRemoveAndVisit(startPos, dotEnd - startPos, node, editGroup); + return dotEnd; + } catch (CoreException e) { + handleException(e); + } + break; + } + case RewriteEvent.REPLACED: { + ASTNode node= (ASTNode) event.getOriginalValue(); + TextEditGroup editGroup= getEditGroup(event); + SourceRange range= getExtendedRange(node); + int offset= range.getStartPosition(); + int length= range.getLength(); + + doTextRemoveAndVisit(offset, length, node, editGroup); + doTextInsert(offset, (ASTNode) event.getNewValue(), getIndent(startPos), true, editGroup); + try { + return getScanner().getTokenEndOffset(TerminalTokens.TokenNameDOT, offset + length); + } catch (CoreException e) { + handleException(e); + } + break; + } + } + } + Object node= getOriginalValue(parent, property); + if (node == null) { + return startPos; + } + int pos= doVisit((ASTNode) node); + try { + return getScanner().getTokenEndOffset(TerminalTokens.TokenNameDOT, pos); + } catch (CoreException e) { + handleException(e); + } + return pos; + } + + class ParagraphListRewriter extends ListRewriter { + + public final static int DEFAULT_SPACING= 1; + + private int initialIndent; + private int separatorLines; + + public ParagraphListRewriter(int initialIndent, int separator) { + this.initialIndent= initialIndent; + this.separatorLines= separator; + } + + protected int getInitialIndent() { + return this.initialIndent; + } + + protected String getSeparatorString(int nodeIndex) { + return getSeparatorString(nodeIndex, nodeIndex + 1); + } + + protected String getSeparatorString(int nodeIndex, int nextNodeIndex) { + int newLines= this.separatorLines == -1 ? getNewLines(nodeIndex) : this.separatorLines; + + String lineDelim= getLineDelimiter(); + StringBuffer buf= new StringBuffer(lineDelim); + for (int i= 0; i < newLines; i++) { + buf.append(lineDelim); + } + buf.append(createIndentString(getNodeIndent(nextNodeIndex))); + return buf.toString(); + } + + private ASTNode getNode(int nodeIndex) { + ASTNode elem= (ASTNode) this.list[nodeIndex].getOriginalValue(); + if (elem == null) { + elem= (ASTNode) this.list[nodeIndex].getNewValue(); + } + return elem; + } + + private int getNewLines(int nodeIndex) { + ASTNode curr= getNode(nodeIndex); + ASTNode next= getNode(nodeIndex + 1); + + int currKind= curr.getNodeType(); + int nextKind= next.getNodeType(); + + ASTNode last= null; + ASTNode secondLast= null; + for (int i= 0; i < this.list.length; i++) { + ASTNode elem= (ASTNode) this.list[i].getOriginalValue(); + if (elem != null) { + if (last != null) { + if (elem.getNodeType() == nextKind && last.getNodeType() == currKind) { + return countEmptyLines(last); + } + secondLast= last; + } + last= elem; + } + } + if (currKind == ASTNode.FIELD_DECLARATION && nextKind == ASTNode.FIELD_DECLARATION ) { + return 0; + } + if (secondLast != null) { + return countEmptyLines(secondLast); + } + return DEFAULT_SPACING; + } + + private int countEmptyLines(ASTNode last) { + LineInformation lineInformation= getLineInformation(); + int lastLine= lineInformation.getLineOfOffset(getExtendedEnd(last)); + if (lastLine >= 0) { + int startLine= lastLine + 1; + int start= lineInformation.getLineOffset(startLine); + if (start < 0) { + return 0; + } + char[] cont= getContent(); + int i= start; + while (i < cont.length && ScannerHelper.isWhitespace(cont[i])) { + i++; + } + if (i > start) { + lastLine= lineInformation.getLineOfOffset(i); + if (lastLine > startLine) { + return lastLine - startLine; + } + } + } + return 0; + } + + protected boolean mustRemoveSeparator(int originalOffset, int nodeIndex) { + // Do not remove separator if the previous non removed node is on the same line and the next node is on another line + int previousNonRemovedNodeIndex = nodeIndex - 1; + while (previousNonRemovedNodeIndex >= 0 && this.list[previousNonRemovedNodeIndex].getChangeKind() == RewriteEvent.REMOVED) { + previousNonRemovedNodeIndex--; + } + + if (previousNonRemovedNodeIndex > -1) { + LineInformation lineInformation = getLineInformation(); + + RewriteEvent prevEvent = this.list[previousNonRemovedNodeIndex]; + int prevKind = prevEvent.getChangeKind(); + if (prevKind == RewriteEvent.UNCHANGED || prevKind == RewriteEvent.REPLACED) { + ASTNode prevNode = (ASTNode) this.list[previousNonRemovedNodeIndex].getOriginalValue(); + int prevEndPosition = prevNode.getStartPosition() + prevNode.getLength(); + int prevLine = lineInformation.getLineOfOffset(prevEndPosition); + int line = lineInformation.getLineOfOffset(originalOffset); + + if (prevLine == line && nodeIndex + 1 < this.list.length) { + RewriteEvent nextEvent = this.list[nodeIndex + 1]; + int nextKind = nextEvent.getChangeKind(); + + if (nextKind == RewriteEvent.UNCHANGED || prevKind == RewriteEvent.REPLACED) { + ASTNode nextNode = (ASTNode) nextEvent.getOriginalValue(); + int nextStartPosition = nextNode.getStartPosition(); + int nextLine = lineInformation.getLineOfOffset(nextStartPosition); + + return nextLine == line; + } + return false; + } + } + } + + return true; + } + } + + private int rewriteParagraphList(ASTNode parent, StructuralPropertyDescriptor property, int insertPos, int insertIndent, int separator, int lead) { + RewriteEvent event= getEvent(parent, property); + if (event == null || event.getChangeKind() == RewriteEvent.UNCHANGED) { + return doVisit(parent, property, insertPos); + } + + RewriteEvent[] events= event.getChildren(); + ParagraphListRewriter listRewriter= new ParagraphListRewriter(insertIndent, separator); + StringBuffer leadString= new StringBuffer(); + if (isAllOfKind(events, RewriteEvent.INSERTED)) { + for (int i= 0; i < lead; i++) { + leadString.append(getLineDelimiter()); + } + leadString.append(createIndentString(insertIndent)); + } + return listRewriter.rewriteList(parent, property, insertPos, leadString.toString()); + } + + private int rewriteOptionalTypeParameters(ASTNode parent, StructuralPropertyDescriptor property, int offset, String keyword, boolean adjustOnNext, boolean needsSpaceOnRemoveAll) { + int pos= offset; + RewriteEvent event= getEvent(parent, property); + if (event != null && event.getChangeKind() != RewriteEvent.UNCHANGED) { + RewriteEvent[] children= event.getChildren(); + try { + boolean isAllInserted= isAllOfKind(children, RewriteEvent.INSERTED); + if (isAllInserted && adjustOnNext) { + pos= getScanner().getNextStartOffset(pos, false); // adjust on next element + } + boolean isAllRemoved= !isAllInserted && isAllOfKind(children, RewriteEvent.REMOVED); + if (isAllRemoved) { // all removed: set start to left bracket + int posBeforeOpenBracket= getScanner().getTokenStartOffset(TerminalTokens.TokenNameLESS, pos); + if (posBeforeOpenBracket != pos) { + needsSpaceOnRemoveAll= false; + } + pos= posBeforeOpenBracket; + } + pos= new ListRewriter().rewriteList(parent, property, pos, String.valueOf('<'), ", "); //$NON-NLS-1$ + if (isAllRemoved) { // all removed: remove right and space up to next element + int endPos= getScanner().getTokenEndOffset(TerminalTokens.TokenNameGREATER, pos); // set pos to '>' + endPos= getScanner().getNextStartOffset(endPos, false); + String replacement= needsSpaceOnRemoveAll ? String.valueOf(' ') : Util.EMPTY_STRING; + doTextReplace(pos, endPos - pos, replacement, getEditGroup(children[children.length - 1])); + return endPos; + } else if (isAllInserted) { + doTextInsert(pos, String.valueOf('>' + keyword), getEditGroup(children[children.length - 1])); + return pos; + } + } catch (CoreException e) { + handleException(e); + } + } else { + pos= doVisit(parent, property, pos); + } + if (pos != offset) { // list contained some type -> parse after closing bracket + try { + return getScanner().getTokenEndOffset(TerminalTokens.TokenNameGREATER, pos); + } catch (CoreException e) { + handleException(e); + } + } + return pos; + } + + private boolean isAllOfKind(RewriteEvent[] children, int kind) { + for (int i= 0; i < children.length; i++) { + if (children[i].getChangeKind() != kind) { + return false; + } + } + return true; + } + + private int rewriteNodeList(ASTNode parent, StructuralPropertyDescriptor property, int pos, String keyword, String separator) { + RewriteEvent event= getEvent(parent, property); + if (event != null && event.getChangeKind() != RewriteEvent.UNCHANGED) { + return new ListRewriter().rewriteList(parent, property, pos, keyword, separator); + } + return doVisit(parent, property, pos); + } + + private void rewriteMethodBody(MethodDeclaration parent, int startPos) { + RewriteEvent event= getEvent(parent, MethodDeclaration.BODY_PROPERTY); + if (event != null) { + switch (event.getChangeKind()) { + case RewriteEvent.INSERTED: { + int endPos= parent.getStartPosition() + parent.getLength(); + TextEditGroup editGroup= getEditGroup(event); + ASTNode body= (ASTNode) event.getNewValue(); + doTextRemove(startPos, endPos - startPos, editGroup); + int indent= getIndent(parent.getStartPosition()); + String prefix= this.formatter.METHOD_BODY.getPrefix(indent); + doTextInsert(startPos, prefix, editGroup); + doTextInsert(startPos, body, indent, true, editGroup); + return; + } + case RewriteEvent.REMOVED: { + TextEditGroup editGroup= getEditGroup(event); + ASTNode body= (ASTNode) event.getOriginalValue(); + int endPos= parent.getStartPosition() + parent.getLength(); + doTextRemoveAndVisit(startPos, endPos - startPos, body, editGroup); + doTextInsert(startPos, ";", editGroup); //$NON-NLS-1$ + return; + } + case RewriteEvent.REPLACED: { + TextEditGroup editGroup= getEditGroup(event); + ASTNode body= (ASTNode) event.getOriginalValue(); + doTextRemoveAndVisit(body.getStartPosition(), body.getLength(), body, editGroup); + doTextInsert(body.getStartPosition(), (ASTNode) event.getNewValue(), getIndent(body.getStartPosition()), true, editGroup); + return; + } + } + } + voidVisit(parent, MethodDeclaration.BODY_PROPERTY); + } + + private int rewriteExtraDimensions(ASTNode parent, StructuralPropertyDescriptor property, int pos) { + RewriteEvent event= getEvent(parent, property); + if (event == null || event.getChangeKind() == RewriteEvent.UNCHANGED) { + return ((Integer) getOriginalValue(parent, property)).intValue(); + } + int oldDim= ((Integer) event.getOriginalValue()).intValue(); + int newDim= ((Integer) event.getNewValue()).intValue(); + + if (oldDim != newDim) { + TextEditGroup editGroup= getEditGroup(event); + rewriteExtraDimensions(oldDim, newDim, pos, editGroup); + } + return oldDim; + } + + private void rewriteExtraDimensions(int oldDim, int newDim, int pos, TextEditGroup editGroup) { + + if (oldDim < newDim) { + for (int i= oldDim; i < newDim; i++) { + doTextInsert(pos, "[]", editGroup); //$NON-NLS-1$ + } + } else if (newDim < oldDim) { + try { + getScanner().setOffset(pos); + for (int i= newDim; i < oldDim; i++) { + getScanner().readToToken(TerminalTokens.TokenNameRBRACKET); + } + doTextRemove(pos, getScanner().getCurrentEndOffset() - pos, editGroup); + } catch (CoreException e) { + handleException(e); + } + } + } + + /* + * Next token is a left brace. Returns the offset after the brace. For incomplete code, return the start offset. + */ + private int getPosAfterLeftBrace(int pos) { + try { + int nextToken= getScanner().readNext(pos, true); + if (nextToken == TerminalTokens.TokenNameLBRACE) { + return getScanner().getCurrentEndOffset(); + } + } catch (CoreException e) { + handleException(e); + } + return pos; + } + + final int getIndent(int offset) { + return this.formatter.computeIndentUnits(getIndentOfLine(offset)); + } + + final void doTextInsert(int insertOffset, ASTNode node, int initialIndentLevel, boolean removeLeadingIndent, TextEditGroup editGroup) { + ArrayList markers= new ArrayList(); + String formatted= this.formatter.getFormattedResult(node, initialIndentLevel, markers); + + + int currPos= 0; + if (removeLeadingIndent) { + while (currPos < formatted.length() && ScannerHelper.isWhitespace(formatted.charAt(currPos))) { + currPos++; + } + } + for (int i= 0; i < markers.size(); i++) { // markers.size can change! + NodeMarker curr= (NodeMarker) markers.get(i); + + int offset= curr.offset; + if (offset != currPos) { + String insertStr= formatted.substring(currPos, offset); + doTextInsert(insertOffset, insertStr, editGroup); // insert until the marker's begin + } + + Object data= curr.data; + if (data instanceof TextEditGroup) { // tracking a node + // need to split and create 2 edits as tracking node can surround replaced node. + TextEdit edit= new RangeMarker(insertOffset, 0); + addEditGroup((TextEditGroup) data, edit); + addEdit(edit); + if (curr.length != 0) { + int end= offset + curr.length; + int k= i + 1; + while (k < markers.size() && ((NodeMarker) markers.get(k)).offset < end) { + k++; + } + curr.offset= end; + curr.length= 0; + markers.add(k, curr); // add again for end position + } + currPos= offset; + } else { + String destIndentString= this.formatter.getIndentString(getCurrentLine(formatted, offset)); + if (data instanceof CopyPlaceholderData) { // replace with a copy/move target + CopySourceInfo copySource= ((CopyPlaceholderData) data).copySource; + int srcIndentLevel= getIndent(copySource.getNode().getStartPosition()); + TextEdit sourceEdit= getCopySourceEdit(copySource); + doTextCopy(sourceEdit, insertOffset, srcIndentLevel, destIndentString, editGroup); + currPos= offset + curr.length; // continue to insert after the replaced string + if (needsNewLineForLineComment(copySource.getNode(), formatted, currPos)) { + doTextInsert(insertOffset, getLineDelimiter(), editGroup); + } + } else if (data instanceof StringPlaceholderData) { // replace with a placeholder + String code= ((StringPlaceholderData) data).code; + String str= this.formatter.changeIndent(code, 0, destIndentString); + doTextInsert(insertOffset, str, editGroup); + currPos= offset + curr.length; // continue to insert after the replaced string + } + } + + } + if (currPos < formatted.length()) { + String insertStr= formatted.substring(currPos); + doTextInsert(insertOffset, insertStr, editGroup); + } + } + + private boolean needsNewLineForLineComment(ASTNode node, String formatted, int offset) { + if (!this.lineCommentEndOffsets.isEndOfLineComment(getExtendedEnd(node), this.content)) { + return false; + } + // copied code ends with a line comment, but doesn't contain the new line + return offset < formatted.length() && !IndentManipulation.isLineDelimiterChar(formatted.charAt(offset)); + } + + private String getCurrentLine(String str, int pos) { + for (int i= pos - 1; i>= 0; i--) { + char ch= str.charAt(i); + if (IndentManipulation.isLineDelimiterChar(ch)) { + return str.substring(i + 1, pos); + } + } + return str.substring(0, pos); + } + + + private void rewriteModifiers(ASTNode parent, StructuralPropertyDescriptor property, int offset) { + RewriteEvent event= getEvent(parent, property); + if (event == null || event.getChangeKind() != RewriteEvent.REPLACED) { + return; + } + try { + int oldModifiers= ((Integer) event.getOriginalValue()).intValue(); + int newModifiers= ((Integer) event.getNewValue()).intValue(); + TextEditGroup editGroup= getEditGroup(event); + + TokenScanner scanner= getScanner(); + + int tok= scanner.readNext(offset, false); + int startPos= scanner.getCurrentStartOffset(); + int nextStart= startPos; + loop: while (true) { + if (TokenScanner.isComment(tok)) { + tok= scanner.readNext(true); // next non-comment token + } + boolean keep= true; + switch (tok) { + case TerminalTokens.TokenNamepublic: keep= Modifier.isPublic(newModifiers); break; + case TerminalTokens.TokenNameprotected: keep= Modifier.isProtected(newModifiers); break; + case TerminalTokens.TokenNameprivate: keep= Modifier.isPrivate(newModifiers); break; + case TerminalTokens.TokenNamestatic: keep= Modifier.isStatic(newModifiers); break; + case TerminalTokens.TokenNamefinal: keep= Modifier.isFinal(newModifiers); break; + case TerminalTokens.TokenNameabstract: keep= Modifier.isAbstract(newModifiers); break; + case TerminalTokens.TokenNamenative: keep= Modifier.isNative(newModifiers); break; + case TerminalTokens.TokenNamevolatile: keep= Modifier.isVolatile(newModifiers); break; + case TerminalTokens.TokenNamestrictfp: keep= Modifier.isStrictfp(newModifiers); break; + case TerminalTokens.TokenNametransient: keep= Modifier.isTransient(newModifiers); break; + case TerminalTokens.TokenNamesynchronized: keep= Modifier.isSynchronized(newModifiers); break; + default: + break loop; + } + tok= getScanner().readNext(false); // include comments + int currPos= nextStart; + nextStart= getScanner().getCurrentStartOffset(); + if (!keep) { + doTextRemove(currPos, nextStart - currPos, editGroup); + } + } + int addedModifiers= newModifiers & ~oldModifiers; + if (addedModifiers != 0) { + if (startPos != nextStart) { + int visibilityModifiers= addedModifiers & (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED); + if (visibilityModifiers != 0) { + StringBuffer buf= new StringBuffer(); + ASTRewriteFlattener.printModifiers(visibilityModifiers, buf); + doTextInsert(startPos, buf.toString(), editGroup); + addedModifiers &= ~visibilityModifiers; + } + } + StringBuffer buf= new StringBuffer(); + ASTRewriteFlattener.printModifiers(addedModifiers, buf); + doTextInsert(nextStart, buf.toString(), editGroup); + } + } catch (CoreException e) { + handleException(e); + } + } + + class ModifierRewriter extends ListRewriter { + + private final Prefix annotationSeparation; + + public ModifierRewriter(Prefix annotationSeparation) { + this.annotationSeparation= annotationSeparation; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer.ListRewriter#getSeparatorString(int) + */ + protected String getSeparatorString(int nodeIndex) { + ASTNode curr= getNewNode(nodeIndex); + if (curr instanceof Annotation) { + return this.annotationSeparation.getPrefix(getNodeIndent(nodeIndex + 1)); + } + return super.getSeparatorString(nodeIndex); + } + } + + + private int rewriteModifiers2(ASTNode node, ChildListPropertyDescriptor property, int pos) { + RewriteEvent event= getEvent(node, property); + if (event == null || event.getChangeKind() == RewriteEvent.UNCHANGED) { + return doVisit(node, property, pos); + } + RewriteEvent[] children= event.getChildren(); + boolean isAllInsert= isAllOfKind(children, RewriteEvent.INSERTED); + boolean isAllRemove= isAllOfKind(children, RewriteEvent.REMOVED); + if (isAllInsert || isAllRemove) { + // update pos + try { + pos= getScanner().getNextStartOffset(pos, false); + } catch (CoreException e) { + handleException(e); + } + } + + Prefix formatterPrefix; + if (property == SingleVariableDeclaration.MODIFIERS2_PROPERTY) + formatterPrefix= this.formatter.PARAM_ANNOTATION_SEPARATION; + else + formatterPrefix= this.formatter.ANNOTATION_SEPARATION; + + int endPos= new ModifierRewriter(formatterPrefix).rewriteList(node, property, pos, "", " "); //$NON-NLS-1$ //$NON-NLS-2$ + + try { + int nextPos= getScanner().getNextStartOffset(endPos, false); + + boolean lastUnchanged= children[children.length - 1].getChangeKind() != RewriteEvent.UNCHANGED; + + if (isAllRemove) { + doTextRemove(endPos, nextPos - endPos, getEditGroup(children[children.length - 1])); + return nextPos; + } else if (isAllInsert || (nextPos == endPos && lastUnchanged)) { // see bug 165654 + RewriteEvent lastChild= children[children.length - 1]; + String separator; + if (lastChild.getNewValue() instanceof Annotation) { + separator= formatterPrefix.getPrefix(getIndent(pos)); + } else { + separator= String.valueOf(' '); + } + doTextInsert(endPos, separator, getEditGroup(lastChild)); + } + } catch (CoreException e) { + handleException(e); + } + return endPos; + } + + + private void replaceOperation(int posBeforeOperation, String newOperation, TextEditGroup editGroup) { + try { + getScanner().readNext(posBeforeOperation, true); + doTextReplace(getScanner().getCurrentStartOffset(), getScanner().getCurrentLength(), newOperation, editGroup); + } catch (CoreException e) { + handleException(e); + } + } + + private void rewriteOperation(ASTNode parent, StructuralPropertyDescriptor property, int posBeforeOperation) { + RewriteEvent event= getEvent(parent, property); + if (event != null && event.getChangeKind() != RewriteEvent.UNCHANGED) { + try { + String newOperation= event.getNewValue().toString(); + TextEditGroup editGroup= getEditGroup(event); + getScanner().readNext(posBeforeOperation, true); + doTextReplace(getScanner().getCurrentStartOffset(), getScanner().getCurrentLength(), newOperation, editGroup); + } catch (CoreException e) { + handleException(e); + } + } + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#postVisit(ASTNode) + */ + public void postVisit(ASTNode node) { + TextEditGroup editGroup= this.eventStore.getTrackedNodeData(node); + if (editGroup != null) { + this.currentEdit= this.currentEdit.getParent(); + } + // remove copy source edits + doCopySourcePostVisit(node, this.sourceCopyEndNodes); + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#preVisit(ASTNode) + */ + public void preVisit(ASTNode node) { + // copies, then range marker + + CopySourceInfo[] infos= this.eventStore.getNodeCopySources(node); + doCopySourcePreVisit(infos, this.sourceCopyEndNodes); + + TextEditGroup editGroup= this.eventStore.getTrackedNodeData(node); + if (editGroup != null) { + SourceRange range= getExtendedRange(node); + int offset= range.getStartPosition(); + int length= range.getLength(); + TextEdit edit= new RangeMarker(offset, length); + addEditGroup(editGroup, edit); + addEdit(edit); + this.currentEdit= edit; + } + + ensureSpaceBeforeReplace(node); + } + + final void doCopySourcePreVisit(CopySourceInfo[] infos, Stack nodeEndStack) { + if (infos != null) { + for (int i= 0; i < infos.length; i++) { + CopySourceInfo curr= infos[i]; + TextEdit edit= getCopySourceEdit(curr); + addEdit(edit); + this.currentEdit= edit; + nodeEndStack.push(curr.getNode()); + } + } + } + + final void doCopySourcePostVisit(ASTNode node, Stack nodeEndStack) { + while (!nodeEndStack.isEmpty() && nodeEndStack.peek() == node) { + nodeEndStack.pop(); + this.currentEdit= this.currentEdit.getParent(); + } + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(CompilationUnit) + */ + public boolean visit(CompilationUnit node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + int startPos= rewriteNode(node, CompilationUnit.PACKAGE_PROPERTY, 0, ASTRewriteFormatter.NONE); + + if (getChangeKind(node, CompilationUnit.PACKAGE_PROPERTY) == RewriteEvent.INSERTED) { + doTextInsert(0, getLineDelimiter(), getEditGroup(node, CompilationUnit.PACKAGE_PROPERTY)); + } + + startPos= rewriteParagraphList(node, CompilationUnit.IMPORTS_PROPERTY, startPos, 0, 0, 2); + rewriteParagraphList(node, CompilationUnit.TYPES_PROPERTY, startPos, 0, -1, 2); + return false; + } + + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(TypeDeclaration) + */ + public boolean visit(TypeDeclaration node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + int apiLevel= node.getAST().apiLevel(); + + int pos= rewriteJavadoc(node, TypeDeclaration.JAVADOC_PROPERTY); + + if (apiLevel == JLS2_INTERNAL) { + rewriteModifiers(node, TypeDeclaration.MODIFIERS_PROPERTY, pos); + } else { + rewriteModifiers2(node, TypeDeclaration.MODIFIERS2_PROPERTY, pos); + } + + boolean isInterface= ((Boolean) getOriginalValue(node, TypeDeclaration.INTERFACE_PROPERTY)).booleanValue(); + // modifiers & class/interface + boolean invertType= isChanged(node, TypeDeclaration.INTERFACE_PROPERTY); + if (invertType) { + try { + int typeToken= isInterface ? TerminalTokens.TokenNameinterface : TerminalTokens.TokenNameclass; + getScanner().readToToken(typeToken, node.getStartPosition()); + + String str= isInterface ? "class" : "interface"; //$NON-NLS-1$ //$NON-NLS-2$ + int start= getScanner().getCurrentStartOffset(); + int end= getScanner().getCurrentEndOffset(); + + doTextReplace(start, end - start, str, getEditGroup(node, TypeDeclaration.INTERFACE_PROPERTY)); + } catch (CoreException e) { + // ignore + } + } + + // name + pos= rewriteRequiredNode(node, TypeDeclaration.NAME_PROPERTY); + + if (apiLevel >= AST.JLS3) { + pos= rewriteOptionalTypeParameters(node, TypeDeclaration.TYPE_PARAMETERS_PROPERTY, pos, "", false, true); //$NON-NLS-1$ + } + + // superclass + if (!isInterface || invertType) { + ChildPropertyDescriptor superClassProperty= (apiLevel == JLS2_INTERNAL) ? TypeDeclaration.SUPERCLASS_PROPERTY : TypeDeclaration.SUPERCLASS_TYPE_PROPERTY; + + RewriteEvent superClassEvent= getEvent(node, superClassProperty); + + int changeKind= superClassEvent != null ? superClassEvent.getChangeKind() : RewriteEvent.UNCHANGED; + switch (changeKind) { + case RewriteEvent.INSERTED: { + doTextInsert(pos, " extends ", getEditGroup(superClassEvent)); //$NON-NLS-1$ + doTextInsert(pos, (ASTNode) superClassEvent.getNewValue(), 0, false, getEditGroup(superClassEvent)); + break; + } + case RewriteEvent.REMOVED: { + ASTNode superClass= (ASTNode) superClassEvent.getOriginalValue(); + int endPos= getExtendedEnd(superClass); + doTextRemoveAndVisit(pos, endPos - pos, superClass, getEditGroup(superClassEvent)); + pos= endPos; + break; + } + case RewriteEvent.REPLACED: { + ASTNode superClass= (ASTNode) superClassEvent.getOriginalValue(); + SourceRange range= getExtendedRange(superClass); + int offset= range.getStartPosition(); + int length= range.getLength(); + doTextRemoveAndVisit(offset, length, superClass, getEditGroup(superClassEvent)); + doTextInsert(offset, (ASTNode) superClassEvent.getNewValue(), 0, false, getEditGroup(superClassEvent)); + pos= offset + length; + break; + } + case RewriteEvent.UNCHANGED: { + pos= doVisit(node, superClassProperty, pos); + } + } + } + // extended interfaces + ChildListPropertyDescriptor superInterfaceProperty= (apiLevel == JLS2_INTERNAL) ? TypeDeclaration.SUPER_INTERFACES_PROPERTY : TypeDeclaration.SUPER_INTERFACE_TYPES_PROPERTY; + + RewriteEvent interfaceEvent= getEvent(node, superInterfaceProperty); + if (interfaceEvent == null || interfaceEvent.getChangeKind() == RewriteEvent.UNCHANGED) { + if (invertType) { + List originalNodes= (List) getOriginalValue(node, superInterfaceProperty); + if (!originalNodes.isEmpty()) { + String keyword= isInterface ? " implements " : " extends "; //$NON-NLS-1$ //$NON-NLS-2$ + ASTNode firstNode= (ASTNode) originalNodes.get(0); + doTextReplace(pos, firstNode.getStartPosition() - pos, keyword, getEditGroup(node, TypeDeclaration.INTERFACE_PROPERTY)); + } + } + pos= doVisit(node, superInterfaceProperty, pos); + } else { + String keyword= (isInterface == invertType) ? " implements " : " extends "; //$NON-NLS-1$ //$NON-NLS-2$ + if (invertType) { + List newNodes= (List) interfaceEvent.getNewValue(); + if (!newNodes.isEmpty()) { + List origNodes= (List) interfaceEvent.getOriginalValue(); + int firstStart= pos; + if (!origNodes.isEmpty()) { + firstStart= ((ASTNode) origNodes.get(0)).getStartPosition(); + } + doTextReplace(pos, firstStart - pos, keyword, getEditGroup(node, TypeDeclaration.INTERFACE_PROPERTY)); + keyword= ""; //$NON-NLS-1$ + pos= firstStart; + } + } + pos= rewriteNodeList(node, superInterfaceProperty, pos, keyword, ", "); //$NON-NLS-1$ + } +//{ObjectTeams: predicate + if (apiLevel == AST.JLS3) { + RewriteEvent predicateEvent= getEvent(node, TypeDeclaration.GUARD_PROPERTY); + int changeKind = rewriteGuardPredicate(predicateEvent, pos); + if (changeKind == RewriteEvent.UNCHANGED) + pos= doVisit(node, TypeDeclaration.GUARD_PROPERTY, pos); + } +// SH} + // type members + // startPos : find position after left brace of type, be aware that bracket might be missing + int startIndent= getIndent(node.getStartPosition()) + 1; + int startPos= getPosAfterLeftBrace(pos); + rewriteParagraphList(node, TypeDeclaration.BODY_DECLARATIONS_PROPERTY, startPos, startIndent, -1, 2); +//{ObjectTeams: precedences: + RewriteEvent precedencesEvent = getEvent(node, TypeDeclaration.PRECEDENCE_PROPERTY); + if ( precedencesEvent == null + || precedencesEvent.getChangeKind() == RewriteEvent.UNCHANGED) + { + pos = doVisit(node, TypeDeclaration.PRECEDENCE_PROPERTY, pos); + } else { + pos = rewriteParagraphList(node, + TypeDeclaration.PRECEDENCE_PROPERTY, + startPos, startIndent, -1, 2); + } +// SH} + return false; + } + + private void rewriteReturnType(MethodDeclaration node, boolean isConstructor, boolean isConstructorChange) { + ChildPropertyDescriptor property= (node.getAST().apiLevel() == JLS2_INTERNAL) ? MethodDeclaration.RETURN_TYPE_PROPERTY : MethodDeclaration.RETURN_TYPE2_PROPERTY; + + // weakness in the AST: return type can exist, even if missing in source + ASTNode originalReturnType= (ASTNode) getOriginalValue(node, property); + boolean returnTypeExists= originalReturnType != null && originalReturnType.getStartPosition() != -1; + if (!isConstructorChange && returnTypeExists) { + rewriteRequiredNode(node, property); + return; + } + // difficult cases: return type insert or remove + ASTNode newReturnType= (ASTNode) getNewValue(node, property); + if (isConstructorChange || !returnTypeExists && newReturnType != originalReturnType) { + // use the start offset of the method name to insert + ASTNode originalMethodName= (ASTNode) getOriginalValue(node, MethodDeclaration.NAME_PROPERTY); + int nextStart= originalMethodName.getStartPosition(); // see bug 84049: can't use extended offset + TextEditGroup editGroup= getEditGroup(node, property); + if (isConstructor || !returnTypeExists) { // insert + doTextInsert(nextStart, newReturnType, getIndent(nextStart), true, editGroup); + doTextInsert(nextStart, " ", editGroup); //$NON-NLS-1$ + } else { // remove up to the method name + int offset= getExtendedOffset(originalReturnType); + doTextRemoveAndVisit(offset, nextStart - offset, originalReturnType, editGroup); + } + } + } + + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(MethodDeclaration) + */ + public boolean visit(MethodDeclaration node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + int pos= rewriteJavadoc(node, MethodDeclaration.JAVADOC_PROPERTY); + if (node.getAST().apiLevel() == JLS2_INTERNAL) { + rewriteModifiers(node, MethodDeclaration.MODIFIERS_PROPERTY, pos); + } else { + pos= rewriteModifiers2(node, MethodDeclaration.MODIFIERS2_PROPERTY, pos); + pos= rewriteOptionalTypeParameters(node, MethodDeclaration.TYPE_PARAMETERS_PROPERTY, pos, " ", true, pos != node.getStartPosition()); //$NON-NLS-1$ + } + + boolean isConstructorChange= isChanged(node, MethodDeclaration.CONSTRUCTOR_PROPERTY); + boolean isConstructor= ((Boolean) getOriginalValue(node, MethodDeclaration.CONSTRUCTOR_PROPERTY)).booleanValue(); + if (!isConstructor || isConstructorChange) { + rewriteReturnType(node, isConstructor, isConstructorChange); + } + // method name + pos= rewriteRequiredNode(node, MethodDeclaration.NAME_PROPERTY); + + // parameters + try { + if (isChanged(node, MethodDeclaration.PARAMETERS_PROPERTY)) { + pos= getScanner().getTokenEndOffset(TerminalTokens.TokenNameLPAREN, pos); + pos= rewriteNodeList(node, MethodDeclaration.PARAMETERS_PROPERTY, pos, "", ", "); //$NON-NLS-1$ //$NON-NLS-2$ + } else { + pos= doVisit(node, MethodDeclaration.PARAMETERS_PROPERTY, pos); + } + + pos= getScanner().getTokenEndOffset(TerminalTokens.TokenNameRPAREN, pos); + + int extraDims= rewriteExtraDimensions(node, MethodDeclaration.EXTRA_DIMENSIONS_PROPERTY, pos); + + boolean hasExceptionChanges= isChanged(node, MethodDeclaration.THROWN_EXCEPTIONS_PROPERTY); + + int bodyChangeKind= getChangeKind(node, MethodDeclaration.BODY_PROPERTY); + + if ((extraDims > 0) && (hasExceptionChanges || bodyChangeKind == RewriteEvent.INSERTED || bodyChangeKind == RewriteEvent.REMOVED)) { + int dim= ((Integer) getOriginalValue(node, MethodDeclaration.EXTRA_DIMENSIONS_PROPERTY)).intValue(); + while (dim > 0) { + pos= getScanner().getTokenEndOffset(TerminalTokens.TokenNameRBRACKET, pos); + dim--; + } + } + + pos= rewriteNodeList(node, MethodDeclaration.THROWN_EXCEPTIONS_PROPERTY, pos, " throws ", ", "); //$NON-NLS-1$ //$NON-NLS-2$ + rewriteMethodBody(node, pos); + } catch (CoreException e) { + // ignore + } + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(Block) + */ + public boolean visit(Block node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + int startPos; + if (isCollapsed(node)) { + startPos= node.getStartPosition(); + } else { + startPos= getPosAfterLeftBrace(node.getStartPosition()); + } + int startIndent= getIndent(node.getStartPosition()) + 1; + rewriteParagraphList(node, Block.STATEMENTS_PROPERTY, startPos, startIndent, 0, 1); + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(ReturnStatement) + */ + public boolean visit(ReturnStatement node) { + try { + this.beforeRequiredSpaceIndex = getScanner().getTokenEndOffset(TerminalTokens.TokenNamereturn, node.getStartPosition()); + + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + ensureSpaceBeforeReplace(node); + + rewriteNode(node, ReturnStatement.EXPRESSION_PROPERTY, this.beforeRequiredSpaceIndex, ASTRewriteFormatter.SPACE); + } catch (CoreException e) { + handleException(e); + } + return false; + } + + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(AnonymousClassDeclaration) + */ + public boolean visit(AnonymousClassDeclaration node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + int startPos= getPosAfterLeftBrace(node.getStartPosition()); + int startIndent= getIndent(node.getStartPosition()) + 1; + rewriteParagraphList(node, AnonymousClassDeclaration.BODY_DECLARATIONS_PROPERTY, startPos, startIndent, -1, 2); + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(ArrayAccess) + */ + public boolean visit(ArrayAccess node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + rewriteRequiredNode(node, ArrayAccess.ARRAY_PROPERTY); + rewriteRequiredNode(node, ArrayAccess.INDEX_PROPERTY); + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(ArrayCreation) + */ + public boolean visit(ArrayCreation node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + ArrayType arrayType= (ArrayType) getOriginalValue(node, ArrayCreation.TYPE_PROPERTY); + int nOldBrackets= getDimensions(arrayType); // number of total brackets + int nNewBrackets= nOldBrackets; + + TextEditGroup editGroup= null; + RewriteEvent typeEvent= getEvent(node, ArrayCreation.TYPE_PROPERTY); + if (typeEvent != null && typeEvent.getChangeKind() == RewriteEvent.REPLACED) { // changed arraytype can have different dimension or type name + ArrayType replacingType= (ArrayType) typeEvent.getNewValue(); + editGroup= getEditGroup(typeEvent); + Type newType= replacingType.getElementType(); + Type oldType= getElementType(arrayType); + if (!newType.equals(oldType)) { + SourceRange range= getExtendedRange(oldType); + int offset= range.getStartPosition(); + int length= range.getLength(); + doTextRemove(offset, length, editGroup); + doTextInsert(offset, newType, 0, false, editGroup); + } + nNewBrackets= replacingType.getDimensions(); // is replaced type + } + voidVisit(arrayType); + + + try { + int offset= getScanner().getTokenStartOffset(TerminalTokens.TokenNameLBRACKET, arrayType.getStartPosition()); + // dimension node with expressions + RewriteEvent dimEvent= getEvent(node, ArrayCreation.DIMENSIONS_PROPERTY); + boolean hasDimensionChanges= (dimEvent != null && dimEvent.getChangeKind() != RewriteEvent.UNCHANGED); + if (hasDimensionChanges) { + RewriteEvent[] events= dimEvent.getChildren(); + // offset on first opening brace + for (int i= 0; i < events.length; i++) { + RewriteEvent event= events[i]; + int changeKind= event.getChangeKind(); + if (changeKind == RewriteEvent.INSERTED) { // insert new dimension + editGroup= getEditGroup(event); + doTextInsert(offset, "[", editGroup); //$NON-NLS-1$ + doTextInsert(offset, (ASTNode) event.getNewValue(), 0, false, editGroup); + doTextInsert(offset, "]", editGroup); //$NON-NLS-1$ + nNewBrackets--; + } else { + ASTNode elem= (ASTNode) event.getOriginalValue(); + int elemEnd= elem.getStartPosition() + elem.getLength(); + int endPos= getScanner().getTokenEndOffset(TerminalTokens.TokenNameRBRACKET, elemEnd); + if (changeKind == RewriteEvent.REMOVED) { + editGroup= getEditGroup(event); + doTextRemoveAndVisit(offset, endPos - offset, elem, editGroup); + } else if (changeKind == RewriteEvent.REPLACED) { + editGroup= getEditGroup(event); + SourceRange range= getExtendedRange(elem); + int elemOffset= range.getStartPosition(); + int elemLength= range.getLength(); + doTextRemoveAndVisit(elemOffset, elemLength, elem, editGroup); + doTextInsert(elemOffset, (ASTNode) event.getNewValue(), 0, false, editGroup); + nNewBrackets--; + } else { + voidVisit(elem); + nNewBrackets--; + } + offset= endPos; + nOldBrackets--; + } + } + } else { + offset= doVisit(node, ArrayCreation.DIMENSIONS_PROPERTY, offset); + } + if (nOldBrackets != nNewBrackets) { + if (!hasDimensionChanges) { + offset= getScanner().getTokenEndOffset(TerminalTokens.TokenNameRBRACKET, offset); + } + rewriteExtraDimensions(nOldBrackets, nNewBrackets, offset, editGroup); + } + + int kind= getChangeKind(node, ArrayCreation.INITIALIZER_PROPERTY); + if (kind == RewriteEvent.REMOVED) { + offset= getScanner().getPreviousTokenEndOffset(TerminalTokens.TokenNameLBRACE, offset); + } else { + offset= node.getStartPosition() + node.getLength(); // insert pos + } + rewriteNode(node, ArrayCreation.INITIALIZER_PROPERTY, offset, ASTRewriteFormatter.SPACE); + } catch (CoreException e) { + handleException(e); + } + return false; + } + + private Type getElementType(ArrayType parent) { + Type t = (Type) getOriginalValue(parent, ArrayType.COMPONENT_TYPE_PROPERTY); + while (t.isArrayType()) { + t = (Type) getOriginalValue(t, ArrayType.COMPONENT_TYPE_PROPERTY); + } + return t; + } + + private int getDimensions(ArrayType parent) { + Type t = (Type) getOriginalValue(parent, ArrayType.COMPONENT_TYPE_PROPERTY); + int dimensions = 1; // always include this array type + while (t.isArrayType()) { + dimensions++; + t = (Type) getOriginalValue(t, ArrayType.COMPONENT_TYPE_PROPERTY); + } + return dimensions; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(ArrayInitializer) + */ + public boolean visit(ArrayInitializer node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + int startPos= getPosAfterLeftBrace(node.getStartPosition()); + rewriteNodeList(node, ArrayInitializer.EXPRESSIONS_PROPERTY, startPos, "", ", "); //$NON-NLS-1$ //$NON-NLS-2$ + return false; + } + + + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(ArrayType) + */ + public boolean visit(ArrayType node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + rewriteRequiredNode(node, ArrayType.COMPONENT_TYPE_PROPERTY); + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(AssertStatement) + */ + public boolean visit(AssertStatement node) { + try { + this.beforeRequiredSpaceIndex = getScanner().getNextEndOffset(node.getStartPosition(), true); + + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + ensureSpaceBeforeReplace(node); + + int offset= rewriteRequiredNode(node, AssertStatement.EXPRESSION_PROPERTY); + rewriteNode(node, AssertStatement.MESSAGE_PROPERTY, offset, ASTRewriteFormatter.ASSERT_COMMENT); + } catch (CoreException e) { + handleException(e); + } + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(Assignment) + */ + public boolean visit(Assignment node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + int pos= rewriteRequiredNode(node, Assignment.LEFT_HAND_SIDE_PROPERTY); + rewriteOperation(node, Assignment.OPERATOR_PROPERTY, pos); + rewriteRequiredNode(node, Assignment.RIGHT_HAND_SIDE_PROPERTY); + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(BooleanLiteral) + */ + public boolean visit(BooleanLiteral node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + Boolean newLiteral= (Boolean) getNewValue(node, BooleanLiteral.BOOLEAN_VALUE_PROPERTY); + TextEditGroup group = getEditGroup(node, BooleanLiteral.BOOLEAN_VALUE_PROPERTY); + doTextReplace(node.getStartPosition(), node.getLength(), newLiteral.toString(), group); + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(BreakStatement) + */ + public boolean visit(BreakStatement node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + try { + int offset= getScanner().getTokenEndOffset(TerminalTokens.TokenNamebreak, node.getStartPosition()); + rewriteNode(node, BreakStatement.LABEL_PROPERTY, offset, ASTRewriteFormatter.SPACE); // space between break and label + } catch (CoreException e) { + handleException(e); + } + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(CastExpression) + */ + public boolean visit(CastExpression node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + rewriteRequiredNode(node, CastExpression.TYPE_PROPERTY); + rewriteRequiredNode(node, CastExpression.EXPRESSION_PROPERTY); + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(CatchClause) + */ + public boolean visit(CatchClause node) { // catch (Exception) Block + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + rewriteRequiredNode(node, CatchClause.EXCEPTION_PROPERTY); + rewriteRequiredNode(node, CatchClause.BODY_PROPERTY); + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(CharacterLiteral) + */ + public boolean visit(CharacterLiteral node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + String escapedSeq= (String) getNewValue(node, CharacterLiteral.ESCAPED_VALUE_PROPERTY); + TextEditGroup group = getEditGroup(node, CharacterLiteral.ESCAPED_VALUE_PROPERTY); + doTextReplace(node.getStartPosition(), node.getLength(), escapedSeq, group); + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(ClassInstanceCreation) + */ + public boolean visit(ClassInstanceCreation node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + int pos= rewriteOptionalQualifier(node, ClassInstanceCreation.EXPRESSION_PROPERTY, node.getStartPosition()); + if (node.getAST().apiLevel() == JLS2_INTERNAL) { + pos= rewriteRequiredNode(node, ClassInstanceCreation.NAME_PROPERTY); + } else { + if (isChanged(node, ClassInstanceCreation.TYPE_ARGUMENTS_PROPERTY)) { + try { + pos= getScanner().getTokenEndOffset(TerminalTokens.TokenNamenew, pos); //after 'new' + rewriteOptionalTypeParameters(node, ClassInstanceCreation.TYPE_ARGUMENTS_PROPERTY, pos, " ", true, true); //$NON-NLS-1$ + } catch (CoreException e) { + handleException(e); + } + } else { + voidVisit(node, ClassInstanceCreation.TYPE_ARGUMENTS_PROPERTY); + } + pos= rewriteRequiredNode(node, ClassInstanceCreation.TYPE_PROPERTY); + } + + if (isChanged(node, ClassInstanceCreation.ARGUMENTS_PROPERTY)) { + try { + int startpos= getScanner().getTokenEndOffset(TerminalTokens.TokenNameLPAREN, pos); + rewriteNodeList(node, ClassInstanceCreation.ARGUMENTS_PROPERTY, startpos, "", ", "); //$NON-NLS-1$ //$NON-NLS-2$ + } catch (CoreException e) { + handleException(e); + } + } else { + voidVisit(node, ClassInstanceCreation.ARGUMENTS_PROPERTY); + } + + int kind= getChangeKind(node, ClassInstanceCreation.ANONYMOUS_CLASS_DECLARATION_PROPERTY); + if (kind == RewriteEvent.REMOVED) { + try { + pos= getScanner().getPreviousTokenEndOffset(TerminalTokens.TokenNameLBRACE, pos); + } catch (CoreException e) { + handleException(e); + } + } else { + pos= node.getStartPosition() + node.getLength(); // insert pos + } + rewriteNode(node, ClassInstanceCreation.ANONYMOUS_CLASS_DECLARATION_PROPERTY, pos, ASTRewriteFormatter.SPACE); + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(ConditionalExpression) + */ + public boolean visit(ConditionalExpression node) { // expression ? thenExpression : elseExpression + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + rewriteRequiredNode(node, ConditionalExpression.EXPRESSION_PROPERTY); + rewriteRequiredNode(node, ConditionalExpression.THEN_EXPRESSION_PROPERTY); + rewriteRequiredNode(node, ConditionalExpression.ELSE_EXPRESSION_PROPERTY); + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(ConstructorInvocation) + */ + public boolean visit(ConstructorInvocation node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + int pos= node.getStartPosition(); + if (node.getAST().apiLevel() >= AST.JLS3) { + pos= rewriteOptionalTypeParameters(node, ConstructorInvocation.TYPE_ARGUMENTS_PROPERTY, pos, "", false, false); //$NON-NLS-1$ + } + try { + pos= getScanner().getTokenEndOffset(TerminalTokens.TokenNameLPAREN, pos); + rewriteNodeList(node, ConstructorInvocation.ARGUMENTS_PROPERTY, pos, "", ", "); //$NON-NLS-1$ //$NON-NLS-2$ + } catch (CoreException e) { + handleException(e); + } + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(ContinueStatement) + */ + public boolean visit(ContinueStatement node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + try { + int offset= getScanner().getTokenEndOffset(TerminalTokens.TokenNamecontinue, node.getStartPosition()); + rewriteNode(node, ContinueStatement.LABEL_PROPERTY, offset, ASTRewriteFormatter.SPACE); // space between continue and label + } catch (CoreException e) { + handleException(e); + } + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(DoStatement) + */ + public boolean visit(DoStatement node) { // do statement while expression + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + int pos= node.getStartPosition(); + try { + RewriteEvent event= getEvent(node, DoStatement.BODY_PROPERTY); + if (event != null && event.getChangeKind() == RewriteEvent.REPLACED) { + int startOffset= getScanner().getTokenEndOffset(TerminalTokens.TokenNamedo, pos); + ASTNode body= (ASTNode) event.getOriginalValue(); + int bodyEnd= body.getStartPosition() + body.getLength(); + int endPos= getScanner().getTokenStartOffset(TerminalTokens.TokenNamewhile, bodyEnd); + rewriteBodyNode(node, DoStatement.BODY_PROPERTY, startOffset, endPos, getIndent(node.getStartPosition()), this.formatter.DO_BLOCK); // body + } else { + voidVisit(node, DoStatement.BODY_PROPERTY); + } + } catch (CoreException e) { + handleException(e); + } + + rewriteRequiredNode(node, DoStatement.EXPRESSION_PROPERTY); + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(EmptyStatement) + */ + public boolean visit(EmptyStatement node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + changeNotSupported(node); // no modification possible + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(ExpressionStatement) + */ + public boolean visit(ExpressionStatement node) { // expression + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + rewriteRequiredNode(node, ExpressionStatement.EXPRESSION_PROPERTY); + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(FieldAccess) + */ + public boolean visit(FieldAccess node) { // expression.name + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + rewriteRequiredNode(node, FieldAccess.EXPRESSION_PROPERTY); // expression + rewriteRequiredNode(node, FieldAccess.NAME_PROPERTY); // name + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(FieldDeclaration) + */ + public boolean visit(FieldDeclaration node) { //{ Modifier } Type VariableDeclarationFragment { ',' VariableDeclarationFragment } ';' + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + int pos= rewriteJavadoc(node, FieldDeclaration.JAVADOC_PROPERTY); + + if (node.getAST().apiLevel() == JLS2_INTERNAL) { + rewriteModifiers(node, FieldDeclaration.MODIFIERS_PROPERTY, pos); + } else { + rewriteModifiers2(node, FieldDeclaration.MODIFIERS2_PROPERTY, pos); + } + + pos= rewriteRequiredNode(node, FieldDeclaration.TYPE_PROPERTY); + rewriteNodeList(node, FieldDeclaration.FRAGMENTS_PROPERTY, pos, "", ", "); //$NON-NLS-1$ //$NON-NLS-2$ + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(ForStatement) + */ + public boolean visit(ForStatement node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + try { + int pos= node.getStartPosition(); + + if (isChanged(node, ForStatement.INITIALIZERS_PROPERTY)) { + // position after opening parent + int startOffset= getScanner().getTokenEndOffset(TerminalTokens.TokenNameLPAREN, pos); + pos= rewriteNodeList(node, ForStatement.INITIALIZERS_PROPERTY, startOffset, "", ", "); //$NON-NLS-1$ //$NON-NLS-2$ + } else { + pos= doVisit(node, ForStatement.INITIALIZERS_PROPERTY, pos); + } + + // position after first semicolon + pos= getScanner().getTokenEndOffset(TerminalTokens.TokenNameSEMICOLON, pos); + + pos= rewriteNode(node, ForStatement.EXPRESSION_PROPERTY, pos, ASTRewriteFormatter.NONE); + + if (isChanged(node, ForStatement.UPDATERS_PROPERTY)) { + int startOffset= getScanner().getTokenEndOffset(TerminalTokens.TokenNameSEMICOLON, pos); + pos= rewriteNodeList(node, ForStatement.UPDATERS_PROPERTY, startOffset, "", ", "); //$NON-NLS-1$ //$NON-NLS-2$ + } else { + pos= doVisit(node, ForStatement.UPDATERS_PROPERTY, pos); + } + + RewriteEvent bodyEvent= getEvent(node, ForStatement.BODY_PROPERTY); + if (bodyEvent != null && bodyEvent.getChangeKind() == RewriteEvent.REPLACED) { + int startOffset= getScanner().getTokenEndOffset(TerminalTokens.TokenNameRPAREN, pos); + rewriteBodyNode(node, ForStatement.BODY_PROPERTY, startOffset, -1, getIndent(node.getStartPosition()), this.formatter.FOR_BLOCK); // body + } else { + voidVisit(node, ForStatement.BODY_PROPERTY); + } + + } catch (CoreException e) { + handleException(e); + } + + + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(IfStatement) + */ + public boolean visit(IfStatement node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + int pos= rewriteRequiredNode(node, IfStatement.EXPRESSION_PROPERTY); // statement + + RewriteEvent thenEvent= getEvent(node, IfStatement.THEN_STATEMENT_PROPERTY); + int elseChange= getChangeKind(node, IfStatement.ELSE_STATEMENT_PROPERTY); + + if (thenEvent != null && thenEvent.getChangeKind() != RewriteEvent.UNCHANGED) { + try { + int tok= getScanner().readNext(pos, true); // after the closing parent + pos= (tok == TerminalTokens.TokenNameRPAREN) ? getScanner().getCurrentEndOffset() : getScanner().getCurrentStartOffset(); + + int indent= getIndent(node.getStartPosition()); + + int endPos= -1; + Object elseStatement= getOriginalValue(node, IfStatement.ELSE_STATEMENT_PROPERTY); + if (elseStatement != null) { + ASTNode thenStatement = (ASTNode) thenEvent.getOriginalValue(); + endPos= getScanner().getTokenStartOffset(TerminalTokens.TokenNameelse, thenStatement.getStartPosition() + thenStatement.getLength()); // else keyword + } + if (elseStatement == null || elseChange != RewriteEvent.UNCHANGED) { + pos= rewriteBodyNode(node, IfStatement.THEN_STATEMENT_PROPERTY, pos, endPos, indent, this.formatter.IF_BLOCK_NO_ELSE); + } else { + pos= rewriteBodyNode(node, IfStatement.THEN_STATEMENT_PROPERTY, pos, endPos, indent, this.formatter.IF_BLOCK_WITH_ELSE); + } + } catch (CoreException e) { + handleException(e); + } + } else { + pos= doVisit(node, IfStatement.THEN_STATEMENT_PROPERTY, pos); + } + + if (elseChange != RewriteEvent.UNCHANGED) { + int indent= getIndent(node.getStartPosition()); + Object newThen= getNewValue(node, IfStatement.THEN_STATEMENT_PROPERTY); + if (newThen instanceof Block) { + rewriteBodyNode(node, IfStatement.ELSE_STATEMENT_PROPERTY, pos, -1, indent, this.formatter.ELSE_AFTER_BLOCK); + } else { + rewriteBodyNode(node, IfStatement.ELSE_STATEMENT_PROPERTY, pos, -1, indent, this.formatter.ELSE_AFTER_STATEMENT); + } + } else { + pos= doVisit(node, IfStatement.ELSE_STATEMENT_PROPERTY, pos); + } + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(ImportDeclaration) + */ + public boolean visit(ImportDeclaration node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + if (node.getAST().apiLevel() >= AST.JLS3) { + RewriteEvent event= getEvent(node, ImportDeclaration.STATIC_PROPERTY); + if (event != null && event.getChangeKind() != RewriteEvent.UNCHANGED) { + try { + int pos= getScanner().getTokenEndOffset(TerminalTokens.TokenNameimport, node.getStartPosition()); + boolean wasStatic= ((Boolean) event.getOriginalValue()).booleanValue(); + if (wasStatic) { + int endPos= getScanner().getTokenEndOffset(TerminalTokens.TokenNamestatic, pos); + doTextRemove(pos, endPos - pos, getEditGroup(event)); + } else { + doTextInsert(pos, " static", getEditGroup(event)); //$NON-NLS-1$ + } + } catch (CoreException e) { + handleException(e); + } + } +//{ObjectTeams: base modifier: + event= getEvent(node, ImportDeclaration.BASE_PROPERTY); + if (event != null && event.getChangeKind() != RewriteEvent.UNCHANGED) { + try { + int pos= getScanner().getTokenEndOffset(TerminalTokens.TokenNameimport, node.getStartPosition()); + boolean wasBase= ((Boolean) event.getOriginalValue()).booleanValue(); + if (wasBase) { + int endPos= getScanner().getTokenEndOffset(TerminalTokens.TokenNamestatic, pos); + doTextRemove(pos, endPos - pos, getEditGroup(event)); + } else { + doTextInsert(pos, " base", getEditGroup(event)); //$NON-NLS-1$ + } + } catch (CoreException e) { + handleException(e); + } + } +// SH} + } + + int pos= rewriteRequiredNode(node, ImportDeclaration.NAME_PROPERTY); + + RewriteEvent event= getEvent(node, ImportDeclaration.ON_DEMAND_PROPERTY); + if (event != null && event.getChangeKind() != RewriteEvent.UNCHANGED) { + boolean isOnDemand= ((Boolean) event.getOriginalValue()).booleanValue(); + if (!isOnDemand) { + doTextInsert(pos, ".*", getEditGroup(event)); //$NON-NLS-1$ + } else { + try { + int endPos= getScanner().getTokenStartOffset(TerminalTokens.TokenNameSEMICOLON, pos); + doTextRemove(pos, endPos - pos, getEditGroup(event)); + } catch (CoreException e) { + handleException(e); + } + } + } + return false; + } + + + + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(InfixExpression) + */ + public boolean visit(InfixExpression node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + int pos= rewriteRequiredNode(node, InfixExpression.LEFT_OPERAND_PROPERTY); + + boolean needsNewOperation= isChanged(node, InfixExpression.OPERATOR_PROPERTY); + String operation= getNewValue(node, InfixExpression.OPERATOR_PROPERTY).toString(); + if (needsNewOperation) { + replaceOperation(pos, operation, getEditGroup(node, InfixExpression.OPERATOR_PROPERTY)); + } + + pos= rewriteRequiredNode(node, InfixExpression.RIGHT_OPERAND_PROPERTY); + + RewriteEvent event= getEvent(node, InfixExpression.EXTENDED_OPERANDS_PROPERTY); + String prefixString= ' ' + operation + ' '; + + if (needsNewOperation) { + int startPos= pos; + TextEditGroup editGroup= getEditGroup(node, InfixExpression.OPERATOR_PROPERTY); + + if (event != null && event.getChangeKind() != RewriteEvent.UNCHANGED) { + RewriteEvent[] extendedOperands= event.getChildren(); + for (int i= 0; i < extendedOperands.length; i++) { + RewriteEvent curr= extendedOperands[i]; + ASTNode elem= (ASTNode) curr.getOriginalValue(); + if (elem != null) { + if (curr.getChangeKind() != RewriteEvent.REPLACED) { + replaceOperation(startPos, operation, editGroup); + } + startPos= elem.getStartPosition() + elem.getLength(); + } + } + } else { + List extendedOperands= (List) getOriginalValue(node, InfixExpression.EXTENDED_OPERANDS_PROPERTY); + for (int i= 0; i < extendedOperands.size(); i++) { + ASTNode elem= (ASTNode) extendedOperands.get(i); + replaceOperation(startPos, operation, editGroup); + startPos= elem.getStartPosition() + elem.getLength(); + } + } + } + rewriteNodeList(node, InfixExpression.EXTENDED_OPERANDS_PROPERTY, pos, prefixString, prefixString); + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(Initializer) + */ + public boolean visit(Initializer node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + int pos= rewriteJavadoc(node, Initializer.JAVADOC_PROPERTY); + if (node.getAST().apiLevel() == JLS2_INTERNAL) { + rewriteModifiers(node, Initializer.MODIFIERS_PROPERTY, pos); + } else { + rewriteModifiers2(node, Initializer.MODIFIERS2_PROPERTY, pos); + } + rewriteRequiredNode(node, Initializer.BODY_PROPERTY); + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(InstanceofExpression) + */ + public boolean visit(InstanceofExpression node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + rewriteRequiredNode(node, InstanceofExpression.LEFT_OPERAND_PROPERTY); + ensureSpaceAfterReplace(node, InstanceofExpression.LEFT_OPERAND_PROPERTY); + rewriteRequiredNode(node, InstanceofExpression.RIGHT_OPERAND_PROPERTY); + return false; + } + + public void ensureSpaceAfterReplace(ASTNode node, ChildPropertyDescriptor desc) { + if (getChangeKind(node, desc) == RewriteEvent.REPLACED) { + int leftOperandEnd= getExtendedEnd((ASTNode) getOriginalValue(node, desc)); + try { + int offset= getScanner().getNextStartOffset(leftOperandEnd, true); // instanceof + + if (offset == leftOperandEnd) { + doTextInsert(offset, String.valueOf(' '), getEditGroup(node, desc)); + } + } catch (CoreException e) { + handleException(e); + } + } + } + + public void ensureSpaceBeforeReplace(ASTNode node) { + if (this.beforeRequiredSpaceIndex == -1) return; + + List events = this.eventStore.getChangedPropertieEvents(node); + + for (Iterator iterator = events.iterator(); iterator.hasNext();) { + RewriteEvent event = (RewriteEvent) iterator.next(); + if (event.getChangeKind() == RewriteEvent.REPLACED && event.getOriginalValue() instanceof ASTNode) { + if (this.beforeRequiredSpaceIndex == getExtendedOffset((ASTNode) event.getOriginalValue())) { + doTextInsert(this.beforeRequiredSpaceIndex , String.valueOf(' '), getEditGroup(event)); + this.beforeRequiredSpaceIndex = -1; + return; + } + } + } + + if (this.beforeRequiredSpaceIndex < getExtendedOffset(node)) { + this.beforeRequiredSpaceIndex = -1; + } + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(Javadoc) + */ + public boolean visit(Javadoc node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + int startPos= node.getStartPosition() + 3; + String separator= getLineDelimiter() + getIndentAtOffset(node.getStartPosition()) + " * "; //$NON-NLS-1$ + + rewriteNodeList(node, Javadoc.TAGS_PROPERTY, startPos, separator, separator); + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(LabeledStatement) + */ + public boolean visit(LabeledStatement node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + rewriteRequiredNode(node, LabeledStatement.LABEL_PROPERTY); + rewriteRequiredNode(node, LabeledStatement.BODY_PROPERTY); + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(MethodInvocation) + */ + public boolean visit(MethodInvocation node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + int pos= rewriteOptionalQualifier(node, MethodInvocation.EXPRESSION_PROPERTY, node.getStartPosition()); + if (node.getAST().apiLevel() >= AST.JLS3) { + pos= rewriteOptionalTypeParameters(node, MethodInvocation.TYPE_ARGUMENTS_PROPERTY, pos, "", false, false); //$NON-NLS-1$ + } + + pos= rewriteRequiredNode(node, MethodInvocation.NAME_PROPERTY); + + if (isChanged(node, MethodInvocation.ARGUMENTS_PROPERTY)) { + // eval position after opening parent + try { + int startOffset= getScanner().getTokenEndOffset(TerminalTokens.TokenNameLPAREN, pos); + rewriteNodeList(node, MethodInvocation.ARGUMENTS_PROPERTY, startOffset, "", ", "); //$NON-NLS-1$ //$NON-NLS-2$ + } catch (CoreException e) { + handleException(e); + } + } else { + voidVisit(node, MethodInvocation.ARGUMENTS_PROPERTY); + } + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(NullLiteral) + */ + public boolean visit(NullLiteral node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + changeNotSupported(node); // no modification possible + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(NumberLiteral) + */ + public boolean visit(NumberLiteral node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + String newLiteral= (String) getNewValue(node, NumberLiteral.TOKEN_PROPERTY); + TextEditGroup group = getEditGroup(node, NumberLiteral.TOKEN_PROPERTY); + doTextReplace(node.getStartPosition(), node.getLength(), newLiteral, group); + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(PackageDeclaration) + */ + public boolean visit(PackageDeclaration node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + if (node.getAST().apiLevel() >= AST.JLS3) { + int pos= rewriteJavadoc(node, PackageDeclaration.JAVADOC_PROPERTY); + rewriteNodeList(node, PackageDeclaration.ANNOTATIONS_PROPERTY, pos, "", " "); //$NON-NLS-1$ //$NON-NLS-2$ + } + + rewriteRequiredNode(node, PackageDeclaration.NAME_PROPERTY); + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(ParenthesizedExpression) + */ + public boolean visit(ParenthesizedExpression node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + rewriteRequiredNode(node, ParenthesizedExpression.EXPRESSION_PROPERTY); + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(PostfixExpression) + */ + public boolean visit(PostfixExpression node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + int pos= rewriteRequiredNode(node, PostfixExpression.OPERAND_PROPERTY); + rewriteOperation(node, PostfixExpression.OPERATOR_PROPERTY, pos); + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(PrefixExpression) + */ + public boolean visit(PrefixExpression node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + rewriteOperation(node, PrefixExpression.OPERATOR_PROPERTY, node.getStartPosition()); + rewriteRequiredNode(node, PrefixExpression.OPERAND_PROPERTY); + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(PrimitiveType) + */ + public boolean visit(PrimitiveType node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + PrimitiveType.Code newCode= (PrimitiveType.Code) getNewValue(node, PrimitiveType.PRIMITIVE_TYPE_CODE_PROPERTY); + TextEditGroup group = getEditGroup(node, PrimitiveType.PRIMITIVE_TYPE_CODE_PROPERTY); + doTextReplace(node.getStartPosition(), node.getLength(), newCode.toString(), group); + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(QualifiedName) + */ + public boolean visit(QualifiedName node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + rewriteRequiredNode(node, QualifiedName.QUALIFIER_PROPERTY); + rewriteRequiredNode(node, QualifiedName.NAME_PROPERTY); + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(SimpleName) + */ + public boolean visit(SimpleName node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + String newString= (String) getNewValue(node, SimpleName.IDENTIFIER_PROPERTY); + TextEditGroup group = getEditGroup(node, SimpleName.IDENTIFIER_PROPERTY); + doTextReplace(node.getStartPosition(), node.getLength(), newString, group); + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(SimpleType) + */ + public boolean visit(SimpleType node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + rewriteRequiredNode(node, SimpleType.NAME_PROPERTY); + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(SingleVariableDeclaration) + */ + public boolean visit(SingleVariableDeclaration node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + int pos= node.getStartPosition(); + if (node.getAST().apiLevel() == JLS2_INTERNAL) { + rewriteModifiers(node, SingleVariableDeclaration.MODIFIERS_PROPERTY, pos); + } else { + rewriteModifiers2(node, SingleVariableDeclaration.MODIFIERS2_PROPERTY, pos); + } + pos= rewriteRequiredNode(node, SingleVariableDeclaration.TYPE_PROPERTY); + if (node.getAST().apiLevel() >= AST.JLS3) { + if (isChanged(node, SingleVariableDeclaration.VARARGS_PROPERTY)) { + if (getNewValue(node, SingleVariableDeclaration.VARARGS_PROPERTY).equals(Boolean.TRUE)) { + doTextInsert(pos, "...", getEditGroup(node, SingleVariableDeclaration.VARARGS_PROPERTY)); //$NON-NLS-1$ + } else { + try { + int ellipsisEnd= getScanner().getNextEndOffset(pos, true); + doTextRemove(pos, ellipsisEnd - pos, getEditGroup(node, SingleVariableDeclaration.VARARGS_PROPERTY)); + } catch (CoreException e) { + handleException(e); + } + } + } + } + + pos= rewriteRequiredNode(node, SingleVariableDeclaration.NAME_PROPERTY); + int extraDims= rewriteExtraDimensions(node, SingleVariableDeclaration.EXTRA_DIMENSIONS_PROPERTY, pos); + + if (extraDims > 0) { + int kind= getChangeKind(node, SingleVariableDeclaration.INITIALIZER_PROPERTY); + if (kind == RewriteEvent.REMOVED) { + try { + pos= getScanner().getPreviousTokenEndOffset(TerminalTokens.TokenNameEQUAL, pos); + } catch (CoreException e) { + handleException(e); + } + } else { + pos= node.getStartPosition() + node.getLength(); // insert pos + } + } + + rewriteNode(node, SingleVariableDeclaration.INITIALIZER_PROPERTY, pos, this.formatter.VAR_INITIALIZER); + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(StringLiteral) + */ + public boolean visit(StringLiteral node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + String escapedSeq= (String) getNewValue(node, StringLiteral.ESCAPED_VALUE_PROPERTY); + TextEditGroup group = getEditGroup(node, StringLiteral.ESCAPED_VALUE_PROPERTY); + doTextReplace(node.getStartPosition(), node.getLength(), escapedSeq, group); + + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(SuperConstructorInvocation) + */ + public boolean visit(SuperConstructorInvocation node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + int pos= rewriteOptionalQualifier(node, SuperConstructorInvocation.EXPRESSION_PROPERTY, node.getStartPosition()); + + if (node.getAST().apiLevel() >= AST.JLS3) { + pos= rewriteOptionalTypeParameters(node, SuperConstructorInvocation.TYPE_ARGUMENTS_PROPERTY, pos, "", false, false); //$NON-NLS-1$ + } + + if (isChanged(node, SuperConstructorInvocation.ARGUMENTS_PROPERTY)) { + // eval position after opening parent + try { + pos= getScanner().getTokenEndOffset(TerminalTokens.TokenNameLPAREN, pos); + rewriteNodeList(node, SuperConstructorInvocation.ARGUMENTS_PROPERTY, pos, "", ", "); //$NON-NLS-1$ //$NON-NLS-2$ + } catch (CoreException e) { + handleException(e); + } + } else { + voidVisit(node, SuperConstructorInvocation.ARGUMENTS_PROPERTY); + } + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(SuperFieldAccess) + */ + public boolean visit(SuperFieldAccess node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + rewriteOptionalQualifier(node, SuperFieldAccess.QUALIFIER_PROPERTY, node.getStartPosition()); + rewriteRequiredNode(node, SuperFieldAccess.NAME_PROPERTY); + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(SuperMethodInvocation) + */ + public boolean visit(SuperMethodInvocation node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + int pos= rewriteOptionalQualifier(node, SuperMethodInvocation.QUALIFIER_PROPERTY, node.getStartPosition()); + + if (node.getAST().apiLevel() >= AST.JLS3) { + if (isChanged(node, SuperMethodInvocation.TYPE_ARGUMENTS_PROPERTY)) { + try { + pos= getScanner().getTokenEndOffset(TerminalTokens.TokenNameDOT, pos); + rewriteOptionalTypeParameters(node, SuperMethodInvocation.TYPE_ARGUMENTS_PROPERTY, pos, "", false, false); //$NON-NLS-1$ + } catch (CoreException e) { + handleException(e); + } + } + } + + pos= rewriteRequiredNode(node, SuperMethodInvocation.NAME_PROPERTY); + + if (isChanged(node, SuperMethodInvocation.ARGUMENTS_PROPERTY)) { + // eval position after opening parent + try { + pos= getScanner().getTokenEndOffset(TerminalTokens.TokenNameLPAREN, pos); + rewriteNodeList(node, SuperMethodInvocation.ARGUMENTS_PROPERTY, pos, "", ", "); //$NON-NLS-1$ //$NON-NLS-2$ + } catch (CoreException e) { + handleException(e); + } + } else { + voidVisit(node, SuperMethodInvocation.ARGUMENTS_PROPERTY); + } + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(SwitchCase) + */ + public boolean visit(SwitchCase node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + // dont allow switching from case to default or back. New statements should be created. + rewriteRequiredNode(node, SwitchCase.EXPRESSION_PROPERTY); + return false; + } + + class SwitchListRewriter extends ParagraphListRewriter { + + private boolean indentSwitchStatementsCompareToCases; + + public SwitchListRewriter(int initialIndent) { + super(initialIndent, 0); + this.indentSwitchStatementsCompareToCases = + DefaultCodeFormatterConstants.TRUE.equals(ASTRewriteAnalyzer.this.options.get(DefaultCodeFormatterConstants.FORMATTER_INDENT_SWITCHSTATEMENTS_COMPARE_TO_CASES)); + } + + protected int getNodeIndent(int nodeIndex) { + int indent= getInitialIndent(); + + if (this.indentSwitchStatementsCompareToCases) { + RewriteEvent event = this.list[nodeIndex]; + int changeKind = event.getChangeKind(); + + ASTNode node; + if (changeKind == RewriteEvent.INSERTED || changeKind == RewriteEvent.REPLACED) { + node= (ASTNode)event.getNewValue(); + } else { + node= (ASTNode)event.getOriginalValue(); + } + + if (node.getNodeType() != ASTNode.SWITCH_CASE) { + indent++; + } + } + return indent; + } + + protected String getSeparatorString(int nodeIndex) { + int total = this.list.length; + + int nextNodeIndex = nodeIndex + 1; + while (nextNodeIndex < total && this.list[nextNodeIndex].getChangeKind() == RewriteEvent.REMOVED) { + nextNodeIndex++; + } + if (nextNodeIndex == total) { + return super.getSeparatorString(nodeIndex); + } + return getSeparatorString(nodeIndex, nextNodeIndex); + } + + protected void updateIndent(int prevMark, int originalOffset, int nodeIndex, TextEditGroup editGroup) { + if (prevMark != RewriteEvent.UNCHANGED && prevMark != RewriteEvent.REPLACED) return; + + // Do not change indent if the previous non removed node is on the same line + int previousNonRemovedNodeIndex = nodeIndex - 1; + while (previousNonRemovedNodeIndex >= 0 && this.list[previousNonRemovedNodeIndex].getChangeKind() == RewriteEvent.REMOVED) { + previousNonRemovedNodeIndex--; + } + + if (previousNonRemovedNodeIndex > -1) { + LineInformation lineInformation = getLineInformation(); + + RewriteEvent prevEvent = this.list[previousNonRemovedNodeIndex]; + int prevKind = prevEvent.getChangeKind(); + if (prevKind == RewriteEvent.UNCHANGED || prevKind == RewriteEvent.REPLACED) { + ASTNode prevNode = (ASTNode) this.list[previousNonRemovedNodeIndex].getOriginalValue(); + int prevEndPosition = prevNode.getStartPosition() + prevNode.getLength(); + int prevLine = lineInformation.getLineOfOffset(prevEndPosition); + int line = lineInformation.getLineOfOffset(originalOffset); + + if (prevLine == line) { + return; + } + } + } + + int total = this.list.length; + while (nodeIndex < total && this.list[nodeIndex].getChangeKind() == RewriteEvent.REMOVED) { + nodeIndex++; + } + + int originalIndent = getIndent(originalOffset); + int newIndent = getNodeIndent(nodeIndex); + + if (originalIndent != newIndent) { + + int line= getLineInformation().getLineOfOffset(originalOffset); + if (line >= 0) { + int lineStart= getLineInformation().getLineOffset(line); + + doTextRemove(lineStart, originalOffset - lineStart, editGroup); // remove previous indentation + doTextInsert(lineStart, createIndentString(newIndent), editGroup); // add new indentation + } + } + } + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(SwitchStatement) + */ + public boolean visit(SwitchStatement node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + int pos= rewriteRequiredNode(node, SwitchStatement.EXPRESSION_PROPERTY); + + ChildListPropertyDescriptor property= SwitchStatement.STATEMENTS_PROPERTY; + if (getChangeKind(node, property) != RewriteEvent.UNCHANGED) { + try { + pos= getScanner().getTokenEndOffset(TerminalTokens.TokenNameLBRACE, pos); + int insertIndent= getIndent(node.getStartPosition()); + if (DefaultCodeFormatterConstants.TRUE.equals(this.options.get(DefaultCodeFormatterConstants.FORMATTER_INDENT_SWITCHSTATEMENTS_COMPARE_TO_SWITCH))) { + insertIndent++; + } + + ParagraphListRewriter listRewriter= new SwitchListRewriter(insertIndent); + StringBuffer leadString= new StringBuffer(); + leadString.append(getLineDelimiter()); + leadString.append(createIndentString(insertIndent)); + listRewriter.rewriteList(node, property, pos, leadString.toString()); + } catch (CoreException e) { + handleException(e); + } + } else { + voidVisit(node, SwitchStatement.STATEMENTS_PROPERTY); + } + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(SynchronizedStatement) + */ + public boolean visit(SynchronizedStatement node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + rewriteRequiredNode(node, SynchronizedStatement.EXPRESSION_PROPERTY); + rewriteRequiredNode(node, SynchronizedStatement.BODY_PROPERTY); + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(ThisExpression) + */ + public boolean visit(ThisExpression node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + rewriteOptionalQualifier(node, ThisExpression.QUALIFIER_PROPERTY, node.getStartPosition()); + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(ThrowStatement) + */ + public boolean visit(ThrowStatement node) { + try { + this.beforeRequiredSpaceIndex = getScanner().getTokenEndOffset(TerminalTokens.TokenNamethrow, node.getStartPosition()); + + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + ensureSpaceBeforeReplace(node); + + rewriteRequiredNode(node, ThrowStatement.EXPRESSION_PROPERTY); + } catch (CoreException e) { + handleException(e); + } + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(TryStatement) + */ + public boolean visit(TryStatement node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + int pos= rewriteRequiredNode(node, TryStatement.BODY_PROPERTY); + + if (isChanged(node, TryStatement.CATCH_CLAUSES_PROPERTY)) { + int indent= getIndent(node.getStartPosition()); + String prefix= this.formatter.CATCH_BLOCK.getPrefix(indent); + pos= rewriteNodeList(node, TryStatement.CATCH_CLAUSES_PROPERTY, pos, prefix, prefix); + } else { + pos= doVisit(node, TryStatement.CATCH_CLAUSES_PROPERTY, pos); + } + rewriteNode(node, TryStatement.FINALLY_PROPERTY, pos, this.formatter.FINALLY_BLOCK); + return false; + } + + + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(TypeDeclarationStatement) + */ + public boolean visit(TypeDeclarationStatement node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + if (node.getAST().apiLevel() == JLS2_INTERNAL) { + rewriteRequiredNode(node, TypeDeclarationStatement.TYPE_DECLARATION_PROPERTY); + } else { + rewriteRequiredNode(node, TypeDeclarationStatement.DECLARATION_PROPERTY); + } + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(TypeLiteral) + */ + public boolean visit(TypeLiteral node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + rewriteRequiredNode(node, TypeLiteral.TYPE_PROPERTY); + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(VariableDeclarationExpression) + */ + public boolean visit(VariableDeclarationExpression node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + // same code as FieldDeclaration + int pos= node.getStartPosition(); + if (node.getAST().apiLevel() == JLS2_INTERNAL) { + rewriteModifiers(node, VariableDeclarationExpression.MODIFIERS_PROPERTY, pos); + } else { + rewriteModifiers2(node, VariableDeclarationExpression.MODIFIERS2_PROPERTY, pos); + } + pos= rewriteRequiredNode(node, VariableDeclarationExpression.TYPE_PROPERTY); + rewriteNodeList(node, VariableDeclarationExpression.FRAGMENTS_PROPERTY, pos, "", ", "); //$NON-NLS-1$ //$NON-NLS-2$ + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(VariableDeclarationFragment) + */ + public boolean visit(VariableDeclarationFragment node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + int pos= rewriteRequiredNode(node, VariableDeclarationFragment.NAME_PROPERTY); + + int extraDims= rewriteExtraDimensions(node, VariableDeclarationFragment.EXTRA_DIMENSIONS_PROPERTY, pos); + + if (extraDims > 0) { + int kind= getChangeKind(node, VariableDeclarationFragment.INITIALIZER_PROPERTY); + if (kind == RewriteEvent.REMOVED) { + try { + pos= getScanner().getPreviousTokenEndOffset(TerminalTokens.TokenNameEQUAL, pos); + } catch (CoreException e) { + handleException(e); + } + } else { + pos= node.getStartPosition() + node.getLength(); // insert pos + } + } + rewriteNode(node, VariableDeclarationFragment.INITIALIZER_PROPERTY, pos, this.formatter.VAR_INITIALIZER); + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(VariableDeclarationStatement) + */ + public boolean visit(VariableDeclarationStatement node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + // same code as FieldDeclaration + int pos= node.getStartPosition(); + if (node.getAST().apiLevel() == JLS2_INTERNAL) { + rewriteModifiers(node, VariableDeclarationStatement.MODIFIERS_PROPERTY, pos); + } else { + rewriteModifiers2(node, VariableDeclarationStatement.MODIFIERS2_PROPERTY, pos); + } + pos= rewriteRequiredNode(node, VariableDeclarationStatement.TYPE_PROPERTY); + + rewriteNodeList(node, VariableDeclarationStatement.FRAGMENTS_PROPERTY, pos, "", ", "); //$NON-NLS-1$ //$NON-NLS-2$ + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(WhileStatement) + */ + public boolean visit(WhileStatement node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + int pos= rewriteRequiredNode(node, WhileStatement.EXPRESSION_PROPERTY); + + try { + if (isChanged(node, WhileStatement.BODY_PROPERTY)) { + int startOffset= getScanner().getTokenEndOffset(TerminalTokens.TokenNameRPAREN, pos); + rewriteBodyNode(node, WhileStatement.BODY_PROPERTY, startOffset, -1, getIndent(node.getStartPosition()), this.formatter.WHILE_BLOCK); // body + } else { + voidVisit(node, WhileStatement.BODY_PROPERTY); + } + } catch (CoreException e) { + handleException(e); + } + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.MemberRef) + */ + public boolean visit(MemberRef node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + rewriteNode(node, MemberRef.QUALIFIER_PROPERTY, node.getStartPosition(), ASTRewriteFormatter.NONE); + + rewriteRequiredNode(node, MemberRef.NAME_PROPERTY); + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.MethodRef) + */ + public boolean visit(MethodRef node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + rewriteNode(node, MethodRef.QUALIFIER_PROPERTY, node.getStartPosition(), ASTRewriteFormatter.NONE); + + int pos= rewriteRequiredNode(node, MethodRef.NAME_PROPERTY); + + if (isChanged(node, MethodRef.PARAMETERS_PROPERTY)) { + // eval position after opening parent + try { + int startOffset= getScanner().getTokenEndOffset(TerminalTokens.TokenNameLPAREN, pos); + rewriteNodeList(node, MethodRef.PARAMETERS_PROPERTY, startOffset, "", ", "); //$NON-NLS-1$ //$NON-NLS-2$ + } catch (CoreException e) { + handleException(e); + } + } else { + voidVisit(node, MethodRef.PARAMETERS_PROPERTY); + } + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.MethodRefParameter) + */ + public boolean visit(MethodRefParameter node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + int pos= rewriteRequiredNode(node, MethodRefParameter.TYPE_PROPERTY); + if (node.getAST().apiLevel() >= AST.JLS3) { + if (isChanged(node, MethodRefParameter.VARARGS_PROPERTY)) { + if (getNewValue(node, MethodRefParameter.VARARGS_PROPERTY).equals(Boolean.TRUE)) { + doTextInsert(pos, "...", getEditGroup(node, MethodRefParameter.VARARGS_PROPERTY)); //$NON-NLS-1$ + } else { + try { + int ellipsisEnd= getScanner().getNextEndOffset(pos, true); + doTextRemove(pos, ellipsisEnd - pos, getEditGroup(node, MethodRefParameter.VARARGS_PROPERTY)); + } catch (CoreException e) { + handleException(e); + } + } + } + } + rewriteNode(node, MethodRefParameter.NAME_PROPERTY, pos, ASTRewriteFormatter.SPACE); + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.TagElement) + */ + public boolean visit(TagElement node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + int changeKind= getChangeKind(node, TagElement.TAG_NAME_PROPERTY); + switch (changeKind) { + case RewriteEvent.INSERTED: { + String newTagName= (String) getNewValue(node, TagElement.TAG_NAME_PROPERTY); + doTextInsert(node.getStartPosition(), newTagName, getEditGroup(node, TagElement.TAG_NAME_PROPERTY)); + break; + } + case RewriteEvent.REMOVED: { + doTextRemove(node.getStartPosition(), findTagNameEnd(node) - node.getStartPosition(), getEditGroup(node, TagElement.TAG_NAME_PROPERTY)); + break; + } + case RewriteEvent.REPLACED: { + String newTagName= (String) getNewValue(node, TagElement.TAG_NAME_PROPERTY); + doTextReplace(node.getStartPosition(), findTagNameEnd(node) - node.getStartPosition(), newTagName, getEditGroup(node, TagElement.TAG_NAME_PROPERTY)); + break; + } + } + + if (isChanged(node, TagElement.FRAGMENTS_PROPERTY)) { + // eval position after name + int endOffset= findTagNameEnd(node); + rewriteNodeList(node, TagElement.FRAGMENTS_PROPERTY, endOffset, " ", " "); //$NON-NLS-1$//$NON-NLS-2$ + } else { + voidVisit(node, TagElement.FRAGMENTS_PROPERTY); + } + return false; + } + + private int findTagNameEnd(TagElement tagNode) { + if (tagNode.getTagName() != null) { + char[] cont= getContent(); + int len= cont.length; + int i= tagNode.getStartPosition(); + while (i < len && !IndentManipulation.isIndentChar(cont[i])) { + i++; + } + return i; + } + return tagNode.getStartPosition(); + } + + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.TextElement) + */ + public boolean visit(TextElement node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + String newText= (String) getNewValue(node, TextElement.TEXT_PROPERTY); + TextEditGroup group = getEditGroup(node, TextElement.TEXT_PROPERTY); + doTextReplace(node.getStartPosition(), node.getLength(), newText, group); + return false; + } + + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.AnnotationTypeDeclaration) + */ + public boolean visit(AnnotationTypeDeclaration node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + int pos= rewriteJavadoc(node, AnnotationTypeDeclaration.JAVADOC_PROPERTY); + rewriteModifiers2(node, AnnotationTypeDeclaration.MODIFIERS2_PROPERTY, pos); + pos= rewriteRequiredNode(node, AnnotationTypeDeclaration.NAME_PROPERTY); + + int startIndent= getIndent(node.getStartPosition()) + 1; + int startPos= getPosAfterLeftBrace(pos); + rewriteParagraphList(node, AnnotationTypeDeclaration.BODY_DECLARATIONS_PROPERTY, startPos, startIndent, -1, 2); + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.AnnotationTypeMemberDeclaration) + */ + public boolean visit(AnnotationTypeMemberDeclaration node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + int pos= rewriteJavadoc(node, AnnotationTypeMemberDeclaration.JAVADOC_PROPERTY); + rewriteModifiers2(node, AnnotationTypeMemberDeclaration.MODIFIERS2_PROPERTY, pos); + rewriteRequiredNode(node, AnnotationTypeMemberDeclaration.TYPE_PROPERTY); + pos= rewriteRequiredNode(node, AnnotationTypeMemberDeclaration.NAME_PROPERTY); + + try { + int changeKind= getChangeKind(node, AnnotationTypeMemberDeclaration.DEFAULT_PROPERTY); + if (changeKind == RewriteEvent.INSERTED || changeKind == RewriteEvent.REMOVED) { + pos= getScanner().getTokenEndOffset(TerminalTokens.TokenNameRPAREN, pos); + } + rewriteNode(node, AnnotationTypeMemberDeclaration.DEFAULT_PROPERTY, pos, this.formatter.ANNOT_MEMBER_DEFAULT); + } catch (CoreException e) { + handleException(e); + } + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.EnhancedForStatement) + */ + public boolean visit(EnhancedForStatement node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + rewriteRequiredNode(node, EnhancedForStatement.PARAMETER_PROPERTY); + int pos= rewriteRequiredNode(node, EnhancedForStatement.EXPRESSION_PROPERTY); + + RewriteEvent bodyEvent= getEvent(node, EnhancedForStatement.BODY_PROPERTY); + if (bodyEvent != null && bodyEvent.getChangeKind() == RewriteEvent.REPLACED) { + int startOffset; + try { + startOffset= getScanner().getTokenEndOffset(TerminalTokens.TokenNameRPAREN, pos); + rewriteBodyNode(node, EnhancedForStatement.BODY_PROPERTY, startOffset, -1, getIndent(node.getStartPosition()), this.formatter.FOR_BLOCK); // body + } catch (CoreException e) { + handleException(e); + } + } else { + voidVisit(node, EnhancedForStatement.BODY_PROPERTY); + } + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.EnumConstantDeclaration) + */ + public boolean visit(EnumConstantDeclaration node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + int pos= rewriteJavadoc(node, EnumConstantDeclaration.JAVADOC_PROPERTY); + rewriteModifiers2(node, EnumConstantDeclaration.MODIFIERS2_PROPERTY, pos); + pos= rewriteRequiredNode(node, EnumConstantDeclaration.NAME_PROPERTY); + RewriteEvent argsEvent= getEvent(node, EnumConstantDeclaration.ARGUMENTS_PROPERTY); + if (argsEvent != null && argsEvent.getChangeKind() != RewriteEvent.UNCHANGED) { + RewriteEvent[] children= argsEvent.getChildren(); + try { + int nextTok= getScanner().readNext(pos, true); + boolean hasParents= (nextTok == TerminalTokens.TokenNameLPAREN); + boolean isAllRemoved= hasParents && isAllOfKind(children, RewriteEvent.REMOVED); + String prefix= ""; //$NON-NLS-1$ + if (!hasParents) { + prefix= "("; //$NON-NLS-1$ + } else if (!isAllRemoved) { + pos= getScanner().getCurrentEndOffset(); + } + pos= rewriteNodeList(node, EnumConstantDeclaration.ARGUMENTS_PROPERTY, pos, prefix, ", "); //$NON-NLS-1$ + + if (!hasParents) { + doTextInsert(pos, ")", getEditGroup(children[children.length - 1])); //$NON-NLS-1$ + } else if (isAllRemoved) { + int afterClosing= getScanner().getNextEndOffset(pos, true); + doTextRemove(pos, afterClosing - pos, getEditGroup(children[children.length - 1])); + pos= afterClosing; + } + } catch (CoreException e) { + handleException(e); + } + } else { + pos= doVisit(node, EnumConstantDeclaration.ARGUMENTS_PROPERTY, pos); + } + + if (isChanged(node, EnumConstantDeclaration.ANONYMOUS_CLASS_DECLARATION_PROPERTY)) { + int kind= getChangeKind(node, EnumConstantDeclaration.ANONYMOUS_CLASS_DECLARATION_PROPERTY); + if (kind == RewriteEvent.REMOVED) { + try { + // 'pos' can be before brace + pos= getScanner().getPreviousTokenEndOffset(TerminalTokens.TokenNameLBRACE, pos); + } catch (CoreException e) { + handleException(e); + } + } else { + pos= node.getStartPosition() + node.getLength(); // insert pos + } + rewriteNode(node, EnumConstantDeclaration.ANONYMOUS_CLASS_DECLARATION_PROPERTY, pos, ASTRewriteFormatter.SPACE); + } + return false; + } + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.EnumDeclaration) + */ + public boolean visit(EnumDeclaration node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + int pos= rewriteJavadoc(node, EnumDeclaration.JAVADOC_PROPERTY); + rewriteModifiers2(node, EnumDeclaration.MODIFIERS2_PROPERTY, pos); + pos= rewriteRequiredNode(node, EnumDeclaration.NAME_PROPERTY); + pos= rewriteNodeList(node, EnumDeclaration.SUPER_INTERFACE_TYPES_PROPERTY, pos, " implements ", ", "); //$NON-NLS-1$ //$NON-NLS-2$ + + pos= getPosAfterLeftBrace(pos); + + String leadString= ""; //$NON-NLS-1$ + RewriteEvent constEvent= getEvent(node, EnumDeclaration.ENUM_CONSTANTS_PROPERTY); + + if (constEvent != null && constEvent.getChangeKind() != RewriteEvent.UNCHANGED) { + RewriteEvent[] events= constEvent.getChildren(); + if (isAllOfKind(events, RewriteEvent.INSERTED)) { + leadString= this.formatter.FIRST_ENUM_CONST.getPrefix(getIndent(node.getStartPosition())); + } + } + pos= rewriteNodeList(node, EnumDeclaration.ENUM_CONSTANTS_PROPERTY, pos, leadString, ", "); //$NON-NLS-1$ + + RewriteEvent bodyEvent= getEvent(node, EnumDeclaration.BODY_DECLARATIONS_PROPERTY); + int indent= 0; + if (bodyEvent != null && bodyEvent.getChangeKind() != RewriteEvent.UNCHANGED) { + boolean hasConstants= !((List) getNewValue(node, EnumDeclaration.ENUM_CONSTANTS_PROPERTY)).isEmpty(); + + RewriteEvent[] children= bodyEvent.getChildren(); + try { + if (hasConstants) { + indent= getIndent(pos); + } else { + indent= getIndent(node.getStartPosition()) + 1; + } + int token= getScanner().readNext(pos, true); + boolean hasSemicolon= token == TerminalTokens.TokenNameSEMICOLON; + if (!hasSemicolon && isAllOfKind(children, RewriteEvent.INSERTED)) { + if (!hasConstants) { + String str= this.formatter.FIRST_ENUM_CONST.getPrefix(indent - 1); + doTextInsert(pos, str, getEditGroup(children[0])); + } + doTextInsert(pos, ";", getEditGroup(children[0])); //$NON-NLS-1$ + } else if (hasSemicolon) { + int endPos= getScanner().getCurrentEndOffset(); + if (isAllOfKind(children, RewriteEvent.REMOVED)) { + doTextRemove(pos, endPos - pos, getEditGroup(children[0])); + } + pos= endPos; + } + } catch (CoreException e) { + handleException(e); + } + } + rewriteParagraphList(node, EnumDeclaration.BODY_DECLARATIONS_PROPERTY, pos, indent, -1, 2); + return false; + } + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.MarkerAnnotation) + */ + public boolean visit(MarkerAnnotation node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + rewriteRequiredNode(node, MarkerAnnotation.TYPE_NAME_PROPERTY); + return false; + } + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.MemberValuePair) + */ + public boolean visit(MemberValuePair node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + rewriteRequiredNode(node, MemberValuePair.NAME_PROPERTY); + rewriteRequiredNode(node, MemberValuePair.VALUE_PROPERTY); + + return false; + } + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.Modifier) + */ + public boolean visit(Modifier node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + String newText= getNewValue(node, Modifier.KEYWORD_PROPERTY).toString(); // type Modifier.ModifierKeyword + TextEditGroup group = getEditGroup(node, Modifier.KEYWORD_PROPERTY); + doTextReplace(node.getStartPosition(), node.getLength(), newText, group); + return false; + } + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.NormalAnnotation) + */ + public boolean visit(NormalAnnotation node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + int pos= rewriteRequiredNode(node, NormalAnnotation.TYPE_NAME_PROPERTY); + if (isChanged(node, NormalAnnotation.VALUES_PROPERTY)) { + // eval position after opening parent + try { + int startOffset= getScanner().getTokenEndOffset(TerminalTokens.TokenNameLPAREN, pos); + rewriteNodeList(node, NormalAnnotation.VALUES_PROPERTY, startOffset, "", ", "); //$NON-NLS-1$ //$NON-NLS-2$ + } catch (CoreException e) { + handleException(e); + } + } else { + voidVisit(node, NormalAnnotation.VALUES_PROPERTY); + } + return false; + } + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ParameterizedType) + */ + public boolean visit(ParameterizedType node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + int pos= rewriteRequiredNode(node, ParameterizedType.TYPE_PROPERTY); + if (isChanged(node, ParameterizedType.TYPE_ARGUMENTS_PROPERTY)) { + // eval position after opening parent + try { + int startOffset= getScanner().getTokenEndOffset(TerminalTokens.TokenNameLESS, pos); + rewriteNodeList(node, ParameterizedType.TYPE_ARGUMENTS_PROPERTY, startOffset, "", ", "); //$NON-NLS-1$ //$NON-NLS-2$ + } catch (CoreException e) { + handleException(e); + } + } else { + voidVisit(node, ParameterizedType.TYPE_ARGUMENTS_PROPERTY); + } + return false; + } + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.QualifiedType) + */ + public boolean visit(QualifiedType node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + rewriteRequiredNode(node, QualifiedType.QUALIFIER_PROPERTY); + rewriteRequiredNode(node, QualifiedType.NAME_PROPERTY); + return false; + } + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.SingleMemberAnnotation) + */ + public boolean visit(SingleMemberAnnotation node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + rewriteRequiredNode(node, SingleMemberAnnotation.TYPE_NAME_PROPERTY); + rewriteRequiredNode(node, SingleMemberAnnotation.VALUE_PROPERTY); + return false; + } + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.TypeParameter) + */ + public boolean visit(TypeParameter node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + int pos= rewriteRequiredNode(node, TypeParameter.NAME_PROPERTY); + if (isChanged(node, TypeParameter.TYPE_BOUNDS_PROPERTY)) { +//{ObjectTeams: <B base R>: + if (node.hasBaseBound()) + rewriteNodeList(node, TypeParameter.TYPE_BOUNDS_PROPERTY, pos, " base ", " & "); //$NON-NLS-1$ //$NON-NLS-2$ + else +// SH} + rewriteNodeList(node, TypeParameter.TYPE_BOUNDS_PROPERTY, pos, " extends ", " & "); //$NON-NLS-1$ //$NON-NLS-2$ + } else { + voidVisit(node, TypeParameter.TYPE_BOUNDS_PROPERTY); + } + return false; + } + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.WildcardType) + */ + public boolean visit(WildcardType node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + try { + int pos= getScanner().getNextEndOffset(node.getStartPosition(), true); // pos after question mark + + Prefix prefix; + if (Boolean.TRUE.equals(getNewValue(node, WildcardType.UPPER_BOUND_PROPERTY))) { + prefix= this.formatter.WILDCARD_EXTENDS; + } else { + prefix= this.formatter.WILDCARD_SUPER; + } + + int boundKindChange= getChangeKind(node, WildcardType.UPPER_BOUND_PROPERTY); + if (boundKindChange != RewriteEvent.UNCHANGED) { + int boundTypeChange= getChangeKind(node, WildcardType.BOUND_PROPERTY); + if (boundTypeChange != RewriteEvent.INSERTED && boundTypeChange != RewriteEvent.REMOVED) { + ASTNode type= (ASTNode) getOriginalValue(node, WildcardType.BOUND_PROPERTY); + String str= prefix.getPrefix(0); + doTextReplace(pos, type.getStartPosition() - pos, str, getEditGroup(node, WildcardType.BOUND_PROPERTY)); + } + } + rewriteNode(node, WildcardType.BOUND_PROPERTY, pos, prefix); + } catch (CoreException e) { + handleException(e); + } + return false; + } + + final void handleException(Throwable e) { + IllegalArgumentException runtimeException= new IllegalArgumentException("Document does not match the AST"); //$NON-NLS-1$ + runtimeException.initCause(e); + throw runtimeException; + } +// {ObjectTeams: visit methods for analyzing OT nodes + public boolean visit(RoleTypeDeclaration node) + { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + int apiLevel= node.getAST().apiLevel(); + + // javadoc + int pos = rewriteJavadoc(node, RoleTypeDeclaration.JAVADOC_PROPERTY); + + // modifier + if(apiLevel == AST.JLS3) + pos = rewriteModifiers2(node, RoleTypeDeclaration.MODIFIERS2_PROPERTY, pos); + else + rewriteModifiers(node, RoleTypeDeclaration.MODIFIERS_PROPERTY, pos); + + boolean isTeam = ((Boolean) getOriginalValue(node, RoleTypeDeclaration.TEAM_PROPERTY)).booleanValue(); + // modifiers & team + boolean invertTeam = isChanged(node, RoleTypeDeclaration.TEAM_PROPERTY); + if (invertTeam) { + if (isTeam) { + try { + getScanner().readToToken(TerminalTokens.TokenNameteam, node.getStartPosition()); + int start= getScanner().getCurrentStartOffset(); + int end= getScanner().getCurrentEndOffset(); + doTextRemove(start, end-start+1, getEditGroup(node, RoleTypeDeclaration.TEAM_PROPERTY)); + } catch (CoreException e) { + // ignore + } + } else { + doTextInsert(pos, " team", getEditGroup(node, RoleTypeDeclaration.TEAM_PROPERTY)); //$NON-NLS-1$ + } + } + + boolean isInterface= ((Boolean) getOriginalValue(node, RoleTypeDeclaration.INTERFACE_PROPERTY)).booleanValue(); + // modifiers & class/interface + boolean invertType= isChanged(node, RoleTypeDeclaration.INTERFACE_PROPERTY); + if (invertType) { + try { + int typeToken= isInterface ? TerminalTokens.TokenNameinterface : TerminalTokens.TokenNameclass; + getScanner().readToToken(typeToken, node.getStartPosition()); + + String str= isInterface ? "class" : "interface"; //$NON-NLS-1$ //$NON-NLS-2$ + int start= getScanner().getCurrentStartOffset(); + int end= getScanner().getCurrentEndOffset(); + + doTextReplace(start, end - start, str, getEditGroup(node, RoleTypeDeclaration.INTERFACE_PROPERTY)); + } catch (CoreException e) { + // ignore + } + } + + // name + pos = rewriteRequiredNode(node, RoleTypeDeclaration.NAME_PROPERTY); + + if (apiLevel >= AST.JLS3) { + pos= rewriteOptionalTypeParameters(node, RoleTypeDeclaration.TYPE_PARAMETERS_PROPERTY, pos, "", false, true); //$NON-NLS-1$ + } + + // superclass + if (!isInterface || invertType) { + ChildPropertyDescriptor superClassProperty= (apiLevel == JLS2_INTERNAL) ? RoleTypeDeclaration.SUPERCLASS_PROPERTY : RoleTypeDeclaration.SUPERCLASS_TYPE_PROPERTY; + + RewriteEvent superClassEvent= getEvent(node, superClassProperty); + + int changeKind= superClassEvent != null ? superClassEvent.getChangeKind() : RewriteEvent.UNCHANGED; + switch (changeKind) { + case RewriteEvent.INSERTED: { + doTextInsert(pos, " extends ", getEditGroup(superClassEvent)); //$NON-NLS-1$ + doTextInsert(pos, (ASTNode) superClassEvent.getNewValue(), 0, false, getEditGroup(superClassEvent)); + break; + } + case RewriteEvent.REMOVED: { + ASTNode superClass= (ASTNode) superClassEvent.getOriginalValue(); + int endPos= getExtendedEnd(superClass); + doTextRemoveAndVisit(pos, endPos - pos, superClass, getEditGroup(superClassEvent)); + pos= endPos; + break; + } + case RewriteEvent.REPLACED: { + ASTNode superClass= (ASTNode) superClassEvent.getOriginalValue(); + SourceRange range= getExtendedRange(superClass); + int offset= range.getStartPosition(); + int length= range.getLength(); + doTextRemoveAndVisit(offset, length, superClass, getEditGroup(superClassEvent)); + doTextInsert(offset, (ASTNode) superClassEvent.getNewValue(), 0, false, getEditGroup(superClassEvent)); + pos= offset + length; + break; + } + case RewriteEvent.UNCHANGED: { + pos= doVisit(node, superClassProperty, pos); + } + } + } + + // extended interfaces + ChildListPropertyDescriptor superInterfaceProperty= (apiLevel == JLS2_INTERNAL) ? RoleTypeDeclaration.SUPER_INTERFACES_PROPERTY : RoleTypeDeclaration.SUPER_INTERFACE_TYPES_PROPERTY; + + RewriteEvent interfaceEvent= getEvent(node, superInterfaceProperty); + if (interfaceEvent == null || interfaceEvent.getChangeKind() == RewriteEvent.UNCHANGED) { + if (invertType) { + List originalNodes= (List) getOriginalValue(node, superInterfaceProperty); + if (!originalNodes.isEmpty()) { + String keyword= isInterface ? " implements " : " extends "; //$NON-NLS-1$ //$NON-NLS-2$ + ASTNode firstNode= (ASTNode) originalNodes.get(0); + doTextReplace(pos, firstNode.getStartPosition() - pos, keyword, getEditGroup(node, RoleTypeDeclaration.INTERFACE_PROPERTY)); + } + } + pos= doVisit(node, superInterfaceProperty, pos); + } else { + String keyword= (isInterface == invertType) ? " implements " : " extends "; //$NON-NLS-1$ //$NON-NLS-2$ + if (invertType) { + List newNodes= (List) interfaceEvent.getNewValue(); + if (!newNodes.isEmpty()) { + List origNodes= (List) interfaceEvent.getOriginalValue(); + int firstStart= pos; + if (!origNodes.isEmpty()) { + firstStart= ((ASTNode) origNodes.get(0)).getStartPosition(); + } + doTextReplace(pos, firstStart - pos, keyword, getEditGroup(node, RoleTypeDeclaration.INTERFACE_PROPERTY)); + keyword= ""; //$NON-NLS-1$ + pos= firstStart; + } + } + pos= rewriteNodeList(node, superInterfaceProperty, pos, keyword, ", "); //$NON-NLS-1$ + } + + + // baseclass + ChildPropertyDescriptor baseClassProperty = (apiLevel == JLS2_INTERNAL)? RoleTypeDeclaration.BASECLASS_PROPERTY : RoleTypeDeclaration.BASECLASS_TYPE_PROPERTY; + RewriteEvent baseClassEvent= getEvent(node, baseClassProperty); + + int changeKind= baseClassEvent != null ? baseClassEvent.getChangeKind() : RewriteEvent.UNCHANGED; + switch (changeKind) { + case RewriteEvent.INSERTED: { + doTextInsert(pos, " playedBy ", getEditGroup(baseClassEvent)); //$NON-NLS-1$ + doTextInsert(pos, (ASTNode) baseClassEvent.getNewValue(), 0, false, getEditGroup(baseClassEvent)); + break; + } + case RewriteEvent.REMOVED: { + ASTNode superClass= (ASTNode) baseClassEvent.getOriginalValue(); + int endPos= getExtendedEnd(superClass); + doTextRemoveAndVisit(pos, endPos - pos, superClass, getEditGroup(baseClassEvent)); + pos= endPos; + break; + } + case RewriteEvent.REPLACED: { + ASTNode superClass= (ASTNode) baseClassEvent.getOriginalValue(); + SourceRange range= getExtendedRange(superClass); + int offset= range.getStartPosition(); + int length= range.getLength(); + doTextRemoveAndVisit(offset, length, superClass, getEditGroup(baseClassEvent)); + doTextInsert(offset, (ASTNode) baseClassEvent.getNewValue(), 0, false, getEditGroup(baseClassEvent)); + pos= offset + length; + break; + } + case RewriteEvent.UNCHANGED: { + pos= doVisit(node, baseClassProperty, pos); + } + } + + // predicate + if (apiLevel == AST.JLS3) { + RewriteEvent predicateEvent= getEvent(node, RoleTypeDeclaration.GUARD_PROPERTY); + changeKind = rewriteGuardPredicate(predicateEvent, pos); + if (changeKind == RewriteEvent.UNCHANGED) + pos= doVisit(node, RoleTypeDeclaration.GUARD_PROPERTY, pos); + } + + // type members + // startPos : find position after left brace of type, be aware that bracket might be missing + int startIndent= getIndent(node.getStartPosition()) + 1; + int startPos= getPosAfterLeftBrace(pos); + pos = rewriteParagraphList(node, RoleTypeDeclaration.BODY_DECLARATIONS_PROPERTY, startPos, startIndent, -1, 2); + + // rewrite precedences + RewriteEvent precedencesEvent = getEvent(node, RoleTypeDeclaration.PRECEDENCE_PROPERTY); + if ( precedencesEvent == null + || precedencesEvent.getChangeKind() == RewriteEvent.UNCHANGED) + { + pos = doVisit(node, RoleTypeDeclaration.PRECEDENCE_PROPERTY, pos); + } else { + pos = rewriteParagraphList(node, + RoleTypeDeclaration.PRECEDENCE_PROPERTY, + pos, startIndent, -1, 2); + } + + return false; + } + private int rewriteGuardPredicate(RewriteEvent predicateEvent, int pos) { + int changeKind= predicateEvent != null ? predicateEvent.getChangeKind() : RewriteEvent.UNCHANGED; + switch (changeKind) { + case RewriteEvent.INSERTED: { + GuardPredicateDeclaration newGuard = (GuardPredicateDeclaration) predicateEvent.getNewValue(); + int indent = getIndent(pos); + doTextInsert(pos, getLineDelimiter(), getEditGroup(predicateEvent)); + doTextInsert(pos, newGuard, indent+1, false, getEditGroup(predicateEvent)); + //doTextInsert(pos, getLineDelimiter(), getEditGroup(predicateEvent)); + break; + } + case RewriteEvent.REMOVED: { + ASTNode predicate = (ASTNode) predicateEvent.getOriginalValue(); + int endPos= getExtendedEnd(predicate); + doTextRemoveAndVisit(pos, endPos - pos, predicate, getEditGroup(predicateEvent)); + pos= endPos; + break; + } + case RewriteEvent.REPLACED: { + ASTNode predicate = (ASTNode) predicateEvent.getOriginalValue(); + SourceRange range= getExtendedRange(predicate); + int offset= range.getStartPosition(); + int length= range.getLength(); + doTextRemoveAndVisit(offset, length, predicate, getEditGroup(predicateEvent)); + doTextInsert(offset, (ASTNode) predicateEvent.getNewValue(), 0, false, getEditGroup(predicateEvent)); + pos= offset + length; + break; + } + } + return changeKind; + } + @Override + public boolean visit(GuardPredicateDeclaration node) { + int pos = node.getStartPosition(); + boolean isBase = ((Boolean) getOriginalValue(node, GuardPredicateDeclaration.BASE_PROPERTY)).booleanValue(); + boolean invertBase = isChanged(node, GuardPredicateDeclaration.BASE_PROPERTY); + if (invertBase) { + if (isBase) { + try { + getScanner().readToToken(TerminalTokens.TokenNamebase, node.getStartPosition()); + int start= getScanner().getCurrentStartOffset(); + int end= getScanner().getCurrentEndOffset(); + doTextRemove(start, end-start+1, getEditGroup(node, GuardPredicateDeclaration.BASE_PROPERTY)); + } catch (CoreException e) { + // ignore + } + } else { + doTextInsert(pos, "base ", getEditGroup(node, GuardPredicateDeclaration.BASE_PROPERTY)); //$NON-NLS-1$ + } + } + + pos = rewriteRequiredNode(node, GuardPredicateDeclaration.EXPRESSION_PROPERTY); + + return false; + } + + @Override + public boolean visit(PrecedenceDeclaration node) { + RewriteEvent precedencesEvent = getEvent(node, PrecedenceDeclaration.ELEMENTS_PROPERTY); + if ( precedencesEvent == null + || precedencesEvent.getChangeKind() == RewriteEvent.UNCHANGED) + { + doVisit(node, PrecedenceDeclaration.ELEMENTS_PROPERTY, 0); + } + else + { + rewriteNodeList(node, + PrecedenceDeclaration.ELEMENTS_PROPERTY, + 0, "", ", "); //$NON-NLS-1$ //$NON-NLS-2$ + } + + return false; + } + + public boolean visit(CalloutMappingDeclaration node) + { + if (!hasChildrenChanges(node) && !hasChildrenChanges(node.bindingOperator())) { // bindingOperator is treated as inline +// System.out.println("visit CalloutMappingDeclaration unchanged"); + return doVisitUnchangedChildren(node); + } + + // javadoc + int pos = rewriteJavadoc(node, CalloutMappingDeclaration.JAVADOC_PROPERTY); + + int posAfterJavadoc = pos; + + // annotations? + if (node.getAST().apiLevel() == JLS2_INTERNAL) { + throw new UnsupportedOperationException("OT/J support for JLS2 is incomplete"); //$NON-NLS-1$ + } else { + pos= rewriteModifiers2(node, CalloutMappingDeclaration.MODIFIERS2_PROPERTY, pos); + } + + // left methodSpec + pos = rewriteRequiredNode(node, CalloutMappingDeclaration.ROLE_MAPPING_ELEMENT_PROPERTY); + + // callout kind + MethodBindingOperator bindingOp = node.bindingOperator(); + int oldBindingKind= ((Integer) getOriginalValue(bindingOp, MethodBindingOperator.BINDING_KIND_PROPERTY)).intValue(); + boolean isCalloutOverride = (oldBindingKind == MethodBindingOperator.KIND_CALLOUT_OVERRIDE); + int typeToken= isCalloutOverride ? TerminalTokens.TokenNameCALLOUT_OVERRIDE : TerminalTokens.TokenNameBINDOUT; + try { + getScanner().readToToken(typeToken, node.getStartPosition()); + } catch (CoreException e) { + handleException(e); + } + pos= getScanner().getCurrentEndOffset(); + + boolean invertCalloutKind= isChanged(bindingOp, MethodBindingOperator.BINDING_KIND_PROPERTY); + if (invertCalloutKind) { + // TODO(jsv) replace with OT constants + String str= isCalloutOverride ? "->" : "=>"; //$NON-NLS-1$ //$NON-NLS-2$ + int start= getScanner().getCurrentStartOffset(); + int end= getScanner().getCurrentEndOffset(); + + doTextReplace(start, end - start, str, getEditGroup(bindingOp, MethodBindingOperator.BINDING_KIND_PROPERTY)); + } + + // right methodSpec + pos = rewriteNode(node, CalloutMappingDeclaration.BASE_MAPPING_ELEMENT_PROPERTY, pos, ASTRewriteFormatter.SPACE); + + // rewrite event + RewriteEvent mappingEvent= getEvent(node, CalloutMappingDeclaration.PARAMETER_MAPPINGS_PROPERTY); + + // no changes in parameter mappings + if (mappingEvent == null || mappingEvent.getChangeKind() == RewriteEvent.UNCHANGED) + { + pos = doVisit(node, CalloutMappingDeclaration.PARAMETER_MAPPINGS_PROPERTY, pos); + if (node.getParameterMappings().isEmpty()) { + boolean haveMappings= false; + try { + if (getScanner().readNext(pos, true) == TerminalTokens.TokenNameSEMICOLON) + haveMappings= true; // EMPTY_MAPPINGS ;-) + } catch (CoreException e) { /* fall through with haveMappings unset: */ } + if (!haveMappings) // ';' not found, insert now: + doTextInsert(pos, ";", getEditGroup(node, CalloutMappingDeclaration.PARAMETER_MAPPINGS_PROPERTY)); //$NON-NLS-1$ + } + } + // changes in parameter mappings + else + { + List newNodes = (List) getNewValue(node, CalloutMappingDeclaration.PARAMETER_MAPPINGS_PROPERTY); + List origNodes = (List) getOriginalValue(node, CalloutMappingDeclaration.PARAMETER_MAPPINGS_PROPERTY); + + if (!newNodes.isEmpty() && origNodes.isEmpty()) + { + // TODO(jsv) format only the with-block with new parameter mapping(s) and not the whole mapping + doTextRemove( + posAfterJavadoc, + (pos-posAfterJavadoc)+1, + getEditGroup(node.getParent(),RoleTypeDeclaration.BODY_DECLARATIONS_PROPERTY) + ); + + doTextInsert( + posAfterJavadoc, + node, + getIndent(node.getParent().getStartPosition()) + 1, + true, + getEditGroup(node.getParent(),RoleTypeDeclaration.BODY_DECLARATIONS_PROPERTY) + ); + + return false; + } + + int startIndent= getIndent(node.getStartPosition()) + 1; + StringBuffer separatorString= new StringBuffer(); + separatorString.append(','); + separatorString.append(getLineDelimiter()); + separatorString.append(createIndentString(startIndent)); + pos = rewriteNodeList( + node, + CalloutMappingDeclaration.PARAMETER_MAPPINGS_PROPERTY, + pos, + "",//$NON-NLS-1$ + separatorString.toString() + ); + + // mappings -> no mappings + if (newNodes.isEmpty() && !origNodes.isEmpty()) + { + try { + getScanner().readToToken(TerminalTokens.TokenNameRBRACE, pos); + } catch (CoreException e) { + handleException(e); + } + + int end = getScanner().getCurrentEndOffset(); + + doTextReplace( + pos, + end - pos, + ";", //$NON-NLS-1$ + getEditGroup(node, CalloutMappingDeclaration.PARAMETER_MAPPINGS_PROPERTY) + ); + } + } + +// System.out.println("visit CalloutMappingDeclaration changed"); + return false; + } + + + public boolean visit(ParameterMapping node) + { + if (!hasChildrenChanges(node)) { +// System.out.println("visit ParameterMapping unchanged"); + return doVisitUnchangedChildren(node); + } + @SuppressWarnings("unused") + int pos; + + + if (node.getDirection().equals("->")) //$NON-NLS-1$ + { + pos = rewriteRequiredNode(node, ParameterMapping.EXPRESSION_PROPERTY); + pos = rewriteRequiredNode(node, ParameterMapping.IDENTIFIER_PROPERTY); + } + else + { + pos = rewriteRequiredNode(node, ParameterMapping.IDENTIFIER_PROPERTY); + pos = rewriteRequiredNode(node, ParameterMapping.EXPRESSION_PROPERTY); + } + +// System.out.println("visit ParameterMapping changed"); + return false; + } + + + public boolean visit(CallinMappingDeclaration node) + { + if (!hasChildrenChanges(node) && !hasChildrenChanges(node.bindingOperator())) { // bindingOperator is treated as inline + return doVisitUnchangedChildren(node); + } + + // javadoc + int pos = rewriteJavadoc(node, CallinMappingDeclaration.JAVADOC_PROPERTY); + int posAfterJavadoc = pos; + + // annotations? + if (node.getAST().apiLevel() == JLS2_INTERNAL) { + throw new UnsupportedOperationException("OT/J support for JLS2 is incomplete"); //$NON-NLS-1$ + } else { + pos= rewriteModifiers2(node, CallinMappingDeclaration.MODIFIERS2_PROPERTY, pos); + } + + // callin name + RewriteEvent event= getEvent(node, CallinMappingDeclaration.NAME_PROPERTY); + if (event != null) { + boolean inserting = event.getChangeKind() == RewriteEvent.INSERTED; + // update pos + try { + pos= getScanner().getNextStartOffset(pos, false); + } catch (CoreException e) { + handleException(e); + } + pos= rewriteNode(node, CallinMappingDeclaration.NAME_PROPERTY, pos, ASTRewriteFormatter.NONE); + if (inserting) + doTextInsert(pos, ": ", getEditGroup(node, CallinMappingDeclaration.NAME_PROPERTY)); //$NON-NLS-1$ + } + + // role methodSpec + pos = rewriteRequiredNode(node, CallinMappingDeclaration.ROLE_MAPPING_ELEMENT_PROPERTY); + + // callin modifier (MISSING_KEYWORD if no valid modifier is given). + pos = rewriteRequiredNode(node.bindingOperator(), MethodBindingOperator.BINDING_MODIFIER_PROPERTY); + + // rewrite base method specs + RewriteEvent baseMethodSpecsEvent = getEvent(node, + CallinMappingDeclaration.BASE_MAPPING_ELEMENTS_PROPERTY); + if (baseMethodSpecsEvent == null + || baseMethodSpecsEvent.getChangeKind() == RewriteEvent.UNCHANGED) + { + pos = doVisit(node, + CallinMappingDeclaration.BASE_MAPPING_ELEMENTS_PROPERTY, + pos); + } + else + { + pos = rewriteNodeList(node, + CallinMappingDeclaration.BASE_MAPPING_ELEMENTS_PROPERTY, + pos, " ", ", "); //$NON-NLS-1$ //$NON-NLS-2$ + } + + // optional guard predicate: + pos = rewriteNode(node, CallinMappingDeclaration.GUARD_PROPERTY, pos, ASTRewriteFormatter.SPACE); + + // rewrite event + RewriteEvent mappingEvent= getEvent(node, CallinMappingDeclaration.PARAMETER_MAPPINGS_PROPERTY); + + // no changes in parameter mappings + if (mappingEvent == null || mappingEvent.getChangeKind() == RewriteEvent.UNCHANGED) + { + pos = doVisit(node, CallinMappingDeclaration.PARAMETER_MAPPINGS_PROPERTY, pos); + if (node.getParameterMappings().isEmpty()) { + boolean haveMappings= false; + try { + if (getScanner().readNext(pos, true) == TerminalTokens.TokenNameSEMICOLON) + haveMappings= true; // EMPTY_MAPPINGS ;-) + } catch (CoreException e) { /* fall through with haveMappings unset: */ } + if (!haveMappings) // ';' not found, insert now: + doTextInsert(pos, ";", getEditGroup(node, CallinMappingDeclaration.PARAMETER_MAPPINGS_PROPERTY)); //$NON-NLS-1$ + } + } + // changes in parameter mappings + else + { + List newNodes = (List) getNewValue(node, CallinMappingDeclaration.PARAMETER_MAPPINGS_PROPERTY); + List origNodes = (List) getOriginalValue(node, CallinMappingDeclaration.PARAMETER_MAPPINGS_PROPERTY); + + if (!newNodes.isEmpty() && origNodes.isEmpty()) + { + // TODO(jsv) format only the with-block with new parameter mapping(s) and not the whole mapping + doTextRemove( + posAfterJavadoc, + (pos-posAfterJavadoc)+1, + getEditGroup(node.getParent(),RoleTypeDeclaration.BODY_DECLARATIONS_PROPERTY) + ); + + doTextInsert( + posAfterJavadoc, + node, + getIndent(node.getParent().getStartPosition()) + 1, + true, + getEditGroup(node.getParent(),RoleTypeDeclaration.BODY_DECLARATIONS_PROPERTY) + ); + + return false; + } + + int startIndent= getIndent(node.getStartPosition()) + 1; + StringBuffer separatorString= new StringBuffer(); + separatorString.append(','); + separatorString.append(getLineDelimiter()); + separatorString.append(createIndentString(startIndent)); + pos = rewriteNodeList( + node, + CallinMappingDeclaration.PARAMETER_MAPPINGS_PROPERTY, + pos, + "",//$NON-NLS-1$ + separatorString.toString() + ); + + // mappings -> no mappings + if (newNodes.isEmpty() && !origNodes.isEmpty()) + { + int rBraceToken= TerminalTokens.TokenNameRBRACE; + try { + getScanner().readToToken(rBraceToken, pos); + } catch (CoreException e) { + handleException(e); + } + + int end = getScanner().getCurrentEndOffset(); + + doTextReplace( + pos, + end - pos, + ";", //$NON-NLS-1$ + getEditGroup(node, CallinMappingDeclaration.PARAMETER_MAPPINGS_PROPERTY) + ); + } + } + + return false; + } + + public boolean visit(MethodBindingOperator node) { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + boolean changedBindingKind= isChanged(node, MethodBindingOperator.BINDING_KIND_PROPERTY); + int pos = node.getStartPosition(); + if (changedBindingKind) { + String str = ""; + switch ((Integer)this.eventStore.getNewValue(node, MethodBindingOperator.BINDING_KIND_PROPERTY)) { + case MethodBindingOperator.KIND_CALLIN : str = CallinMappingDeclaration.CALLIN; break; + case MethodBindingOperator.KIND_CALLOUT : str = CalloutMappingDeclaration.CALLOUT; break; + case MethodBindingOperator.KIND_CALLOUT_OVERRIDE : str = CalloutMappingDeclaration.CALLOUT_OVERRIDE; break; + } + doTextReplace(pos, 2, str, getEditGroup(node, MethodBindingOperator.BINDING_KIND_PROPERTY)); + } + if (node.bindingModifier() != null) + pos = node.bindingModifier().getStartPosition(); + else + pos+=2; + rewriteNode(node, MethodBindingOperator.BINDING_MODIFIER_PROPERTY, pos, ASTRewriteFormatter.NONE); + return false; + } + + public boolean visit(MethodSpec node) + { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + int pos= node.getStartPosition(); + // type parameters + if (node.getAST().apiLevel() == AST.JLS3) { + pos= rewriteOptionalTypeParameters(node, MethodSpec.TYPE_PARAMETERS_PROPERTY, pos, " ", true, false); //$NON-NLS-1$ + } + // return type + rewriteRequiredNode(node, MethodSpec.RETURN_TYPE2_PROPERTY); + // method name + pos= rewriteRequiredNode(node, MethodSpec.NAME_PROPERTY); + + // parameters + try { + if (isChanged(node, MethodSpec.PARAMETERS_PROPERTY)) { + pos= getScanner().getTokenEndOffset(TerminalTokens.TokenNameLPAREN, pos); + pos= rewriteNodeList(node, MethodSpec.PARAMETERS_PROPERTY, pos, "", ", "); //$NON-NLS-1$ //$NON-NLS-2$ + } else { + pos= doVisit(node, MethodSpec.PARAMETERS_PROPERTY, pos); + } + } catch (CoreException e) { + // ignore + } + return false; + } + + //FIXME(SH): XXX COMPLETE THESE!!! + + public boolean visit(FieldAccessSpec node) + { + if (!hasChildrenChanges(node)) { +// System.out.println("visit FieldAccessSpec unchanged"); + return doVisitUnchangedChildren(node); + } +// System.out.println("visit FieldAccessSpec changed"); + return true; + } + + public boolean visit(LiftingType node) + { + if (!hasChildrenChanges(node)) { +// System.out.println("visit LiftingType unchanged"); + return doVisitUnchangedChildren(node); + } +// System.out.println("visit LiftingType changed"); + return true; + } + + // FIXME(SH): test these: + + public boolean visit(TypeAnchor node) + { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + rewriteRequiredNode(node, TypeAnchor.PATH_PROPERTY); + return false; + } + + //  copied from structurally equivalent WhileStatement: + public boolean visit(WithinStatement node) + { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + int pos= rewriteRequiredNode(node, WithinStatement.TEAM_EXPRESSION_PROPERTY); + + try { + if (isChanged(node, WithinStatement.BODY_PROPERTY)) { + int startOffset= getScanner().getTokenEndOffset(TerminalTokens.TokenNameRPAREN, pos); + rewriteBodyNode(node, WithinStatement.BODY_PROPERTY, startOffset, -1, getIndent(node.getStartPosition()), this.formatter.WHILE_BLOCK); // body // FIXME(SH): WITHIN_BLOCK? + } else { + voidVisit(node, WithinStatement.BODY_PROPERTY); + } + } catch (CoreException e) { + handleException(e); + } + return false; + } + + // copied from structurally equivalent SuperMethodInvocation + public boolean visit(TSuperMessageSend node) + { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + int pos= rewriteOptionalQualifier(node, TSuperMessageSend.QUALIFIER_PROPERTY, node.getStartPosition()); + + // no type arguments + + pos= rewriteRequiredNode(node, TSuperMessageSend.NAME_PROPERTY); + + if (isChanged(node, TSuperMessageSend.ARGUMENTS_PROPERTY)) { + // eval position after opening parent + try { + pos= getScanner().getTokenEndOffset(TerminalTokens.TokenNameLPAREN, pos); + rewriteNodeList(node, TSuperMessageSend.ARGUMENTS_PROPERTY, pos, "", ", "); //$NON-NLS-1$ //$NON-NLS-2$ + } catch (CoreException e) { + handleException(e); + } + } else { + voidVisit(node, TSuperMessageSend.ARGUMENTS_PROPERTY); + } + return false; + } + + // copied from structurally equivalent SuperConstructorInvocation + public boolean visit(TSuperConstructorInvocation node) + { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + // no qualifying expression + + // no type arguments + + // added for OT: + int pos= node.getStartPosition(); + + if (isChanged(node, TSuperConstructorInvocation.ARGUMENTS_PROPERTY)) { + // eval position after opening parent + try { + pos= getScanner().getTokenEndOffset(TerminalTokens.TokenNameLPAREN, pos); + rewriteNodeList(node, TSuperConstructorInvocation.ARGUMENTS_PROPERTY, pos, "", ", "); //$NON-NLS-1$ //$NON-NLS-2$ + } catch (CoreException e) { + handleException(e); + } + } else { + voidVisit(node, TSuperConstructorInvocation.ARGUMENTS_PROPERTY); + } + return false; + } + + // copied from structurally equivalent SuperMethodInvocation + public boolean visit(BaseCallMessageSend node) + { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + // no qualifier + int pos= node.getStartPosition(); + + // no type arguments + + pos= rewriteRequiredNode(node, BaseCallMessageSend.NAME_PROPERTY); + + if (isChanged(node, BaseCallMessageSend.ARGUMENTS_PROPERTY)) { + // eval position after opening parent + try { + pos= getScanner().getTokenEndOffset(TerminalTokens.TokenNameLPAREN, pos); + rewriteNodeList(node, BaseCallMessageSend.ARGUMENTS_PROPERTY, pos, "", ", "); //$NON-NLS-1$ //$NON-NLS-2$ + } catch (CoreException e) { + handleException(e); + } + } else { + voidVisit(node, BaseCallMessageSend.ARGUMENTS_PROPERTY); + } + return false; + } + + // cf. TSuperConstructorInvocation: + public boolean visit(BaseConstructorInvocation node) + { + if (!hasChildrenChanges(node)) { + return doVisitUnchangedChildren(node); + } + + // no qualifying expression + + // no type arguments + + // added for OT: + int pos= node.getStartPosition(); + + if (isChanged(node, BaseConstructorInvocation.ARGUMENTS_PROPERTY)) { + // eval position after opening parent + try { + pos= getScanner().getTokenEndOffset(TerminalTokens.TokenNameLPAREN, pos); + rewriteNodeList(node, BaseConstructorInvocation.ARGUMENTS_PROPERTY, pos, "", ", "); //$NON-NLS-1$ //$NON-NLS-2$ + } catch (CoreException e) { + handleException(e); + } + } else { + voidVisit(node, BaseConstructorInvocation.ARGUMENTS_PROPERTY); + } + return false; + } +//jsv} + +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteFlattener.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteFlattener.java new file mode 100644 index 000000000..1f6d9a06f --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteFlattener.java @@ -0,0 +1,1754 @@ +/******************************************************************************* + * Copyright (c) 2000, 2010 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 + * $Id: ASTRewriteFlattener.java 23214 2010-01-07 19:51:00Z stephan $ + * + * Contributors: + * IBM Corporation - initial API and implementation + * Fraunhofer FIRST - extended API and implementation + * Technical University Berlin - extended API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.core.dom.rewrite; + +import java.util.List; + +import org.eclipse.jdt.core.dom.*; +import org.eclipse.jdt.internal.compiler.util.Util; + +public class ASTRewriteFlattener extends ASTVisitor { + + /** + * Internal synonynm for deprecated constant AST.JSL2 + * to alleviate deprecation warnings. + * @deprecated + */ + /*package*/ static final int JLS2_INTERNAL = AST.JLS2; + + public static String asString(ASTNode node, RewriteEventStore store) { + ASTRewriteFlattener flattener= new ASTRewriteFlattener(store); + node.accept(flattener); + return flattener.getResult(); + } + + protected StringBuffer result; + private RewriteEventStore store; + + public ASTRewriteFlattener(RewriteEventStore store) { + this.store= store; + this.result= new StringBuffer(); + } + + /** + * Returns the string accumulated in the visit. + * + * @return the serialized + */ + public String getResult() { + // convert to a string, but lose any extra space in the string buffer by copying + return new String(this.result.toString()); + } + + /** + * Resets this printer so that it can be used again. + */ + public void reset() { + this.result.setLength(0); + } + + /** + * Appends the text representation of the given modifier flags, followed by a single space. + * + * @param modifiers the modifiers + * @param buf The <code>StringBuffer</code> to write the result to. + */ + public static void printModifiers(int modifiers, StringBuffer buf) { + if (Modifier.isPublic(modifiers)) { + buf.append("public "); //$NON-NLS-1$ + } + if (Modifier.isProtected(modifiers)) { + buf.append("protected "); //$NON-NLS-1$ + } + if (Modifier.isPrivate(modifiers)) { + buf.append("private "); //$NON-NLS-1$ + } + if (Modifier.isStatic(modifiers)) { + buf.append("static "); //$NON-NLS-1$ + } + if (Modifier.isAbstract(modifiers)) { + buf.append("abstract "); //$NON-NLS-1$ + } + if (Modifier.isFinal(modifiers)) { + buf.append("final "); //$NON-NLS-1$ + } + if (Modifier.isSynchronized(modifiers)) { + buf.append("synchronized "); //$NON-NLS-1$ + } + if (Modifier.isVolatile(modifiers)) { + buf.append("volatile "); //$NON-NLS-1$ + } + if (Modifier.isNative(modifiers)) { + buf.append("native "); //$NON-NLS-1$ + } + if (Modifier.isStrictfp(modifiers)) { + buf.append("strictfp "); //$NON-NLS-1$ + } + if (Modifier.isTransient(modifiers)) { + buf.append("transient "); //$NON-NLS-1$ + } + +//{ObjectTeams: printModifier for OT-specific modifiers + if (Modifier.isReplace(modifiers)) + { + buf.append("replace "); //$NON-NLS-1$ + } + if (Modifier.isBefore(modifiers)) + { + buf.append("before "); //$NON-NLS-1$ + } + if (Modifier.isAfter(modifiers)) + { + buf.append("after "); //$NON-NLS-1$ + } + if (Modifier.isGet(modifiers)) + { + buf.append("get "); //$NON-NLS-1$ + } + if (Modifier.isSet(modifiers)) + { + buf.append("set "); //$NON-NLS-1$ + } + if (Modifier.isTeam(modifiers)) + { + buf.append("team "); //$NON-NLS-1$ + } + if (Modifier.isCallin(modifiers)) + { + buf.append("callin "); //$NON-NLS-1$ + } +// jsv} + + } + + protected List getChildList(ASTNode parent, StructuralPropertyDescriptor childProperty) { + return (List) getAttribute(parent, childProperty); + } + + protected ASTNode getChildNode(ASTNode parent, StructuralPropertyDescriptor childProperty) { + return (ASTNode) getAttribute(parent, childProperty); + } + + protected int getIntAttribute(ASTNode parent, StructuralPropertyDescriptor childProperty) { + return ((Integer) getAttribute(parent, childProperty)).intValue(); + } + + protected boolean getBooleanAttribute(ASTNode parent, StructuralPropertyDescriptor childProperty) { + return ((Boolean) getAttribute(parent, childProperty)).booleanValue(); + } + + protected Object getAttribute(ASTNode parent, StructuralPropertyDescriptor childProperty) { + return this.store.getNewValue(parent, childProperty); + } + + protected void visitList(ASTNode parent, StructuralPropertyDescriptor childProperty, String separator) { + List list= getChildList(parent, childProperty); + for (int i= 0; i < list.size(); i++) { + if (separator != null && i > 0) { + this.result.append(separator); + } + ((ASTNode) list.get(i)).accept(this); + } + } + + protected void visitList(ASTNode parent, StructuralPropertyDescriptor childProperty, String separator, String lead, String post) { + List list= getChildList(parent, childProperty); + if (!list.isEmpty()) { + this.result.append(lead); + for (int i= 0; i < list.size(); i++) { + if (separator != null && i > 0) { + this.result.append(separator); + } + ((ASTNode) list.get(i)).accept(this); + } + this.result.append(post); + } + } + + + /* + * @see ASTVisitor#visit(AnonymousClassDeclaration) + */ + public boolean visit(AnonymousClassDeclaration node) { + this.result.append('{'); + visitList(node, AnonymousClassDeclaration.BODY_DECLARATIONS_PROPERTY, null); + this.result.append('}'); + return false; + } + + /* + * @see ASTVisitor#visit(ArrayAccess) + */ + public boolean visit(ArrayAccess node) { + getChildNode(node, ArrayAccess.ARRAY_PROPERTY).accept(this); + this.result.append('['); + getChildNode(node, ArrayAccess.INDEX_PROPERTY).accept(this); + this.result.append(']'); + return false; + } + + /* + * @see ASTVisitor#visit(ArrayCreation) + */ + public boolean visit(ArrayCreation node) { + this.result.append("new "); //$NON-NLS-1$ + ArrayType arrayType= (ArrayType) getChildNode(node, ArrayCreation.TYPE_PROPERTY); + + // get the element type and count dimensions + Type elementType= (Type) getChildNode(arrayType, ArrayType.COMPONENT_TYPE_PROPERTY); + int dimensions= 1; // always include this array type + while (elementType.isArrayType()) { + dimensions++; + elementType = (Type) getChildNode(elementType, ArrayType.COMPONENT_TYPE_PROPERTY); + } + + elementType.accept(this); + + List list= getChildList(node, ArrayCreation.DIMENSIONS_PROPERTY); + for (int i= 0; i < list.size(); i++) { + this.result.append('['); + ((ASTNode) list.get(i)).accept(this); + this.result.append(']'); + dimensions--; + } + + // add empty "[]" for each extra array dimension + for (int i= 0; i < dimensions; i++) { + this.result.append("[]"); //$NON-NLS-1$ + } + ASTNode initializer= getChildNode(node, ArrayCreation.INITIALIZER_PROPERTY); + if (initializer != null) { + getChildNode(node, ArrayCreation.INITIALIZER_PROPERTY).accept(this); + } + return false; + } + + /* + * @see ASTVisitor#visit(ArrayInitializer) + */ + public boolean visit(ArrayInitializer node) { + this.result.append('{'); + visitList(node, ArrayInitializer.EXPRESSIONS_PROPERTY, String.valueOf(',')); + this.result.append('}'); + return false; + } + + /* + * @see ASTVisitor#visit(ArrayType) + */ + public boolean visit(ArrayType node) { + getChildNode(node, ArrayType.COMPONENT_TYPE_PROPERTY).accept(this); + this.result.append("[]"); //$NON-NLS-1$ + return false; + } + + /* + * @see ASTVisitor#visit(AssertStatement) + */ + public boolean visit(AssertStatement node) { + this.result.append("assert "); //$NON-NLS-1$ + getChildNode(node, AssertStatement.EXPRESSION_PROPERTY).accept(this); + + ASTNode message= getChildNode(node, AssertStatement.MESSAGE_PROPERTY); + if (message != null) { + this.result.append(':'); + message.accept(this); + } + this.result.append(';'); + return false; + } + + /* + * @see ASTVisitor#visit(Assignment) + */ + public boolean visit(Assignment node) { + getChildNode(node, Assignment.LEFT_HAND_SIDE_PROPERTY).accept(this); + this.result.append(getAttribute(node, Assignment.OPERATOR_PROPERTY).toString()); + getChildNode(node, Assignment.RIGHT_HAND_SIDE_PROPERTY).accept(this); + return false; + } + + + + /* + * @see ASTVisitor#visit(Block) + */ + public boolean visit(Block node) { + this.result.append('{'); + visitList(node, Block.STATEMENTS_PROPERTY, null); + this.result.append('}'); + return false; + } + + /* + * @see ASTVisitor#visit(BooleanLiteral) + */ + public boolean visit(BooleanLiteral node) { + if (node.booleanValue() == true) { + this.result.append("true"); //$NON-NLS-1$ + } else { + this.result.append("false"); //$NON-NLS-1$ + } + return false; + } + + /* + * @see ASTVisitor#visit(BreakStatement) + */ + public boolean visit(BreakStatement node) { + this.result.append("break"); //$NON-NLS-1$ + ASTNode label= getChildNode(node, BreakStatement.LABEL_PROPERTY); + if (label != null) { + this.result.append(' '); + label.accept(this); + } + this.result.append(';'); + return false; + } + + /* + * @see ASTVisitor#visit(CastExpression) + */ + public boolean visit(CastExpression node) { + this.result.append('('); + getChildNode(node, CastExpression.TYPE_PROPERTY).accept(this); + this.result.append(')'); + getChildNode(node, CastExpression.EXPRESSION_PROPERTY).accept(this); + return false; + } + + /* + * @see ASTVisitor#visit(CatchClause) + */ + public boolean visit(CatchClause node) { + this.result.append("catch ("); //$NON-NLS-1$ + getChildNode(node, CatchClause.EXCEPTION_PROPERTY).accept(this); + this.result.append(')'); + getChildNode(node, CatchClause.BODY_PROPERTY).accept(this); + return false; + } + + /* + * @see ASTVisitor#visit(CharacterLiteral) + */ + public boolean visit(CharacterLiteral node) { + this.result.append(getAttribute(node, CharacterLiteral.ESCAPED_VALUE_PROPERTY)); + return false; + } + + /* + * @see ASTVisitor#visit(ClassInstanceCreation) + */ + public boolean visit(ClassInstanceCreation node) { + ASTNode expression= getChildNode(node, ClassInstanceCreation.EXPRESSION_PROPERTY); + if (expression != null) { + expression.accept(this); + this.result.append('.'); + } + this.result.append("new ");//$NON-NLS-1$ + if (node.getAST().apiLevel() == JLS2_INTERNAL) { + getChildNode(node, ClassInstanceCreation.NAME_PROPERTY).accept(this); + } else { + visitList(node, ClassInstanceCreation.TYPE_ARGUMENTS_PROPERTY, String.valueOf(','), String.valueOf('<'), String.valueOf('>')); + getChildNode(node, ClassInstanceCreation.TYPE_PROPERTY).accept(this); + } + + this.result.append('('); + visitList(node, ClassInstanceCreation.ARGUMENTS_PROPERTY, String.valueOf(',')); + this.result.append(')'); + ASTNode decl= getChildNode(node, ClassInstanceCreation.ANONYMOUS_CLASS_DECLARATION_PROPERTY); + if (decl != null) { + decl.accept(this); + } + return false; + } + + /* + * @see ASTVisitor#visit(CompilationUnit) + */ + public boolean visit(CompilationUnit node) { + ASTNode pack= getChildNode(node, CompilationUnit.PACKAGE_PROPERTY); + if (pack != null) { + pack.accept(this); + } + visitList(node, CompilationUnit.IMPORTS_PROPERTY, null); + visitList(node, CompilationUnit.TYPES_PROPERTY, null); + return false; + } + + /* + * @see ASTVisitor#visit(ConditionalExpression) + */ + public boolean visit(ConditionalExpression node) { + getChildNode(node, ConditionalExpression.EXPRESSION_PROPERTY).accept(this); + this.result.append('?'); + getChildNode(node, ConditionalExpression.THEN_EXPRESSION_PROPERTY).accept(this); + this.result.append(':'); + getChildNode(node, ConditionalExpression.ELSE_EXPRESSION_PROPERTY).accept(this); + return false; + } + + /* + * @see ASTVisitor#visit(ConstructorInvocation) + */ + public boolean visit(ConstructorInvocation node) { + if (node.getAST().apiLevel() >= AST.JLS3) { + visitList(node, ConstructorInvocation.TYPE_ARGUMENTS_PROPERTY, String.valueOf(','), String.valueOf('<'), String.valueOf('>')); + } + this.result.append("this("); //$NON-NLS-1$ + visitList(node, ConstructorInvocation.ARGUMENTS_PROPERTY, String.valueOf(',')); + this.result.append(");"); //$NON-NLS-1$ + return false; + } + + /* + * @see ASTVisitor#visit(ContinueStatement) + */ + public boolean visit(ContinueStatement node) { + this.result.append("continue"); //$NON-NLS-1$ + ASTNode label= getChildNode(node, ContinueStatement.LABEL_PROPERTY); + if (label != null) { + this.result.append(' '); + label.accept(this); + } + this.result.append(';'); + return false; + } + + /* + * @see ASTVisitor#visit(DoStatement) + */ + public boolean visit(DoStatement node) { + this.result.append("do "); //$NON-NLS-1$ + getChildNode(node, DoStatement.BODY_PROPERTY).accept(this); + this.result.append(" while ("); //$NON-NLS-1$ + getChildNode(node, DoStatement.EXPRESSION_PROPERTY).accept(this); + this.result.append(");"); //$NON-NLS-1$ + return false; + } + + /* + * @see ASTVisitor#visit(EmptyStatement) + */ + public boolean visit(EmptyStatement node) { + this.result.append(';'); + return false; + } + + /* + * @see ASTVisitor#visit(ExpressionStatement) + */ + public boolean visit(ExpressionStatement node) { + getChildNode(node, ExpressionStatement.EXPRESSION_PROPERTY).accept(this); + this.result.append(';'); + return false; + } + + /* + * @see ASTVisitor#visit(FieldAccess) + */ + public boolean visit(FieldAccess node) { + getChildNode(node, FieldAccess.EXPRESSION_PROPERTY).accept(this); + this.result.append('.'); + getChildNode(node, FieldAccess.NAME_PROPERTY).accept(this); + return false; + } + + /* + * @see ASTVisitor#visit(FieldDeclaration) + */ + public boolean visit(FieldDeclaration node) { + ASTNode javadoc= getChildNode(node, FieldDeclaration.JAVADOC_PROPERTY); + if (javadoc != null) { + javadoc.accept(this); + } + if (node.getAST().apiLevel() == JLS2_INTERNAL) { + printModifiers(getIntAttribute(node, FieldDeclaration.MODIFIERS_PROPERTY), this.result); + } else { + visitList(node, FieldDeclaration.MODIFIERS2_PROPERTY, String.valueOf(' '), Util.EMPTY_STRING, String.valueOf(' ')); + } + getChildNode(node, FieldDeclaration.TYPE_PROPERTY).accept(this); + this.result.append(' '); + visitList(node, FieldDeclaration.FRAGMENTS_PROPERTY, String.valueOf(',')); + this.result.append(';'); + return false; + } + + /* + * @see ASTVisitor#visit(ForStatement) + */ + public boolean visit(ForStatement node) { + this.result.append("for ("); //$NON-NLS-1$ + visitList(node, ForStatement.INITIALIZERS_PROPERTY, String.valueOf(',')); + this.result.append(';'); + ASTNode expression= getChildNode(node, ForStatement.EXPRESSION_PROPERTY); + if (expression != null) { + expression.accept(this); + } + this.result.append(';'); + visitList(node, ForStatement.UPDATERS_PROPERTY, String.valueOf(',')); + this.result.append(')'); + getChildNode(node, ForStatement.BODY_PROPERTY).accept(this); + return false; + } + + /* + * @see ASTVisitor#visit(IfStatement) + */ + public boolean visit(IfStatement node) { + this.result.append("if ("); //$NON-NLS-1$ + getChildNode(node, IfStatement.EXPRESSION_PROPERTY).accept(this); + this.result.append(')'); + getChildNode(node, IfStatement.THEN_STATEMENT_PROPERTY).accept(this); + ASTNode elseStatement= getChildNode(node, IfStatement.ELSE_STATEMENT_PROPERTY); + if (elseStatement != null) { + this.result.append(" else "); //$NON-NLS-1$ + elseStatement.accept(this); + } + return false; + } + + /* + * @see ASTVisitor#visit(ImportDeclaration) + */ + public boolean visit(ImportDeclaration node) { + this.result.append("import "); //$NON-NLS-1$ + if (node.getAST().apiLevel() >= AST.JLS3) { + if (getBooleanAttribute(node, ImportDeclaration.STATIC_PROPERTY)) { + this.result.append("static ");//$NON-NLS-1$ + } +//{ObjectTeams: one more modifier: + if (getBooleanAttribute(node, ImportDeclaration.BASE_PROPERTY)) { + this.result.append("base ");//$NON-NLS-1$ + } +// SH} + } + getChildNode(node, ImportDeclaration.NAME_PROPERTY).accept(this); + if (getBooleanAttribute(node, ImportDeclaration.ON_DEMAND_PROPERTY)) { + this.result.append(".*"); //$NON-NLS-1$ + } + this.result.append(';'); + return false; + } + + + + /* + * @see ASTVisitor#visit(InfixExpression) + */ + public boolean visit(InfixExpression node) { + getChildNode(node, InfixExpression.LEFT_OPERAND_PROPERTY).accept(this); + this.result.append(' '); + String operator= getAttribute(node, InfixExpression.OPERATOR_PROPERTY).toString(); + + this.result.append(operator); + this.result.append(' '); + getChildNode(node, InfixExpression.RIGHT_OPERAND_PROPERTY).accept(this); + + List list= getChildList(node, InfixExpression.EXTENDED_OPERANDS_PROPERTY); + for (int i= 0; i < list.size(); i++) { + this.result.append(operator); + ((ASTNode) list.get(i)).accept(this); + } + return false; + } + + /* + * @see ASTVisitor#visit(InstanceofExpression) + */ + public boolean visit(InstanceofExpression node) { + getChildNode(node, InstanceofExpression.LEFT_OPERAND_PROPERTY).accept(this); + this.result.append(" instanceof "); //$NON-NLS-1$ + getChildNode(node, InstanceofExpression.RIGHT_OPERAND_PROPERTY).accept(this); + return false; + } + + /* + * @see ASTVisitor#visit(Initializer) + */ + public boolean visit(Initializer node) { + ASTNode javadoc= getChildNode(node, Initializer.JAVADOC_PROPERTY); + if (javadoc != null) { + javadoc.accept(this); + } + if (node.getAST().apiLevel() == JLS2_INTERNAL) { + printModifiers(getIntAttribute(node, Initializer.MODIFIERS_PROPERTY), this.result); + } else { + visitList(node, Initializer.MODIFIERS2_PROPERTY, String.valueOf(' '), Util.EMPTY_STRING, String.valueOf(' ')); + } + getChildNode(node, Initializer.BODY_PROPERTY).accept(this); + return false; + } + + /* + * @see ASTVisitor#visit(Javadoc) + */ + public boolean visit(Javadoc node) { + this.result.append("/**"); //$NON-NLS-1$ + List list= getChildList(node, Javadoc.TAGS_PROPERTY); + for (int i= 0; i < list.size(); i++) { + this.result.append("\n * "); //$NON-NLS-1$ + ((ASTNode) list.get(i)).accept(this); + } + this.result.append("\n */"); //$NON-NLS-1$ + return false; + } + + /* + * @see ASTVisitor#visit(LabeledStatement) + */ + public boolean visit(LabeledStatement node) { + getChildNode(node, LabeledStatement.LABEL_PROPERTY).accept(this); + this.result.append(": "); //$NON-NLS-1$ + getChildNode(node, LabeledStatement.BODY_PROPERTY).accept(this); + return false; + } + + /* + * @see ASTVisitor#visit(MethodDeclaration) + */ + public boolean visit(MethodDeclaration node) { + ASTNode javadoc= getChildNode(node, MethodDeclaration.JAVADOC_PROPERTY); + if (javadoc != null) { + javadoc.accept(this); + } + if (node.getAST().apiLevel() == JLS2_INTERNAL) { + printModifiers(getIntAttribute(node, MethodDeclaration.MODIFIERS_PROPERTY), this.result); + } else { + visitList(node, MethodDeclaration.MODIFIERS2_PROPERTY, String.valueOf(' '), Util.EMPTY_STRING, String.valueOf(' ')); + visitList(node, MethodDeclaration.TYPE_PARAMETERS_PROPERTY, String.valueOf(','), String.valueOf('<'), String.valueOf('>')); + } + + if (!getBooleanAttribute(node, MethodDeclaration.CONSTRUCTOR_PROPERTY)) { + if (node.getAST().apiLevel() == JLS2_INTERNAL) { + getChildNode(node, MethodDeclaration.RETURN_TYPE_PROPERTY).accept(this); + } else { + ASTNode returnType = getChildNode(node, MethodDeclaration.RETURN_TYPE2_PROPERTY); + if (returnType != null) { + returnType.accept(this); + } else { + // methods really ought to have a return type + this.result.append("void");//$NON-NLS-1$ + } + } + this.result.append(' '); + } + getChildNode(node, MethodDeclaration.NAME_PROPERTY).accept(this); + this.result.append('('); + visitList(node, MethodDeclaration.PARAMETERS_PROPERTY, String.valueOf(',')); + this.result.append(')'); + int extraDims= getIntAttribute(node, MethodDeclaration.EXTRA_DIMENSIONS_PROPERTY); + for (int i = 0; i < extraDims; i++) { + this.result.append("[]"); //$NON-NLS-1$ + } + visitList(node, MethodDeclaration.THROWN_EXCEPTIONS_PROPERTY, String.valueOf(','), " throws ", Util.EMPTY_STRING); //$NON-NLS-1$ +//{ObjectTeams: predicate + ASTNode guardPredicate = getChildNode(node, MethodDeclaration.GUARD_PROPERTY); + if (guardPredicate != null) { + guardPredicate.accept(this); + this.result.append(' '); + } +// SH} + ASTNode body= getChildNode(node, MethodDeclaration.BODY_PROPERTY); + if (body == null) { + this.result.append(';'); + } else { + body.accept(this); + } + return false; + } + + /* + * @see ASTVisitor#visit(MethodInvocation) + */ + public boolean visit(MethodInvocation node) { + ASTNode expression= getChildNode(node, MethodInvocation.EXPRESSION_PROPERTY); + if (expression != null) { + expression.accept(this); + this.result.append('.'); + } + if (node.getAST().apiLevel() >= AST.JLS3) { + visitList(node, MethodInvocation.TYPE_ARGUMENTS_PROPERTY, String.valueOf(','), String.valueOf('<'), String.valueOf('>')); + } + + getChildNode(node, MethodInvocation.NAME_PROPERTY).accept(this); + this.result.append('('); + visitList(node, MethodInvocation.ARGUMENTS_PROPERTY, String.valueOf(',')); + this.result.append(')'); + return false; + } + + /* + * @see ASTVisitor#visit(NullLiteral) + */ + public boolean visit(NullLiteral node) { + this.result.append("null"); //$NON-NLS-1$ + return false; + } + + /* + * @see ASTVisitor#visit(NumberLiteral) + */ + public boolean visit(NumberLiteral node) { + this.result.append(getAttribute(node, NumberLiteral.TOKEN_PROPERTY).toString()); + return false; + } + + /* + * @see ASTVisitor#visit(PackageDeclaration) + */ + public boolean visit(PackageDeclaration node) { + if (node.getAST().apiLevel() >= AST.JLS3) { + ASTNode javadoc = getChildNode(node, PackageDeclaration.JAVADOC_PROPERTY); + if (javadoc != null) { + javadoc.accept(this); + } + visitList(node, PackageDeclaration.ANNOTATIONS_PROPERTY, String.valueOf(' ')); + } + this.result.append("package "); //$NON-NLS-1$ + getChildNode(node, PackageDeclaration.NAME_PROPERTY).accept(this); + this.result.append(';'); + return false; + } + + /* + * @see ASTVisitor#visit(ParenthesizedExpression) + */ + public boolean visit(ParenthesizedExpression node) { + this.result.append('('); + getChildNode(node, ParenthesizedExpression.EXPRESSION_PROPERTY).accept(this); + this.result.append(')'); + return false; + } + + /* + * @see ASTVisitor#visit(PostfixExpression) + */ + public boolean visit(PostfixExpression node) { + getChildNode(node, PostfixExpression.OPERAND_PROPERTY).accept(this); + this.result.append(getAttribute(node, PostfixExpression.OPERATOR_PROPERTY).toString()); + return false; + } + + /* + * @see ASTVisitor#visit(PrefixExpression) + */ + public boolean visit(PrefixExpression node) { + this.result.append(getAttribute(node, PrefixExpression.OPERATOR_PROPERTY).toString()); + getChildNode(node, PrefixExpression.OPERAND_PROPERTY).accept(this); + return false; + } + + /* + * @see ASTVisitor#visit(PrimitiveType) + */ + public boolean visit(PrimitiveType node) { + this.result.append(getAttribute(node, PrimitiveType.PRIMITIVE_TYPE_CODE_PROPERTY).toString()); + return false; + } + + /* + * @see ASTVisitor#visit(QualifiedName) + */ + public boolean visit(QualifiedName node) { + getChildNode(node, QualifiedName.QUALIFIER_PROPERTY).accept(this); + this.result.append('.'); + getChildNode(node, QualifiedName.NAME_PROPERTY).accept(this); + return false; + } + + /* + * @see ASTVisitor#visit(ReturnStatement) + */ + public boolean visit(ReturnStatement node) { + this.result.append("return"); //$NON-NLS-1$ + ASTNode expression= getChildNode(node, ReturnStatement.EXPRESSION_PROPERTY); + if (expression != null) { + this.result.append(' '); + expression.accept(this); + } + this.result.append(';'); + return false; + } + + /* + * @see ASTVisitor#visit(SimpleName) + */ + public boolean visit(SimpleName node) { + this.result.append(getAttribute(node, SimpleName.IDENTIFIER_PROPERTY)); + return false; + } + + /* + * @see ASTVisitor#visit(SimpleType) + */ + public boolean visit(SimpleType node) { + return true; + } + + /* + * @see ASTVisitor#visit(SingleVariableDeclaration) + */ + public boolean visit(SingleVariableDeclaration node) { + if (node.getAST().apiLevel() == JLS2_INTERNAL) { + printModifiers(getIntAttribute(node, SingleVariableDeclaration.MODIFIERS_PROPERTY), this.result); + } else { + visitList(node, SingleVariableDeclaration.MODIFIERS2_PROPERTY, String.valueOf(' '), Util.EMPTY_STRING, String.valueOf(' ')); + } + getChildNode(node, SingleVariableDeclaration.TYPE_PROPERTY).accept(this); + if (node.getAST().apiLevel() >= AST.JLS3) { + if (getBooleanAttribute(node, SingleVariableDeclaration.VARARGS_PROPERTY)) { + this.result.append("...");//$NON-NLS-1$ + } + } + this.result.append(' '); + getChildNode(node, SingleVariableDeclaration.NAME_PROPERTY).accept(this); + int extraDimensions= getIntAttribute(node, SingleVariableDeclaration.EXTRA_DIMENSIONS_PROPERTY); + for (int i = 0; i < extraDimensions; i++) { + this.result.append("[]"); //$NON-NLS-1$ + } + ASTNode initializer= getChildNode(node, SingleVariableDeclaration.INITIALIZER_PROPERTY); + if (initializer != null) { + this.result.append('='); + initializer.accept(this); + } + return false; + } + + /* + * @see ASTVisitor#visit(StringLiteral) + */ + public boolean visit(StringLiteral node) { + this.result.append(getAttribute(node, StringLiteral.ESCAPED_VALUE_PROPERTY)); + return false; + } + + /* + * @see ASTVisitor#visit(SuperConstructorInvocation) + */ + public boolean visit(SuperConstructorInvocation node) { + ASTNode expression= getChildNode(node, SuperConstructorInvocation.EXPRESSION_PROPERTY); + if (expression != null) { + expression.accept(this); + this.result.append('.'); + } + if (node.getAST().apiLevel() >= AST.JLS3) { + visitList(node, SuperConstructorInvocation.TYPE_ARGUMENTS_PROPERTY, String.valueOf(','), String.valueOf('<'), String.valueOf('>')); + } + this.result.append("super("); //$NON-NLS-1$ + visitList(node, SuperConstructorInvocation.ARGUMENTS_PROPERTY, String.valueOf(',')); + this.result.append(");"); //$NON-NLS-1$ + return false; + } + + /* + * @see ASTVisitor#visit(SuperFieldAccess) + */ + public boolean visit(SuperFieldAccess node) { + ASTNode qualifier= getChildNode(node, SuperFieldAccess.QUALIFIER_PROPERTY); + if (qualifier != null) { + qualifier.accept(this); + this.result.append('.'); + } + this.result.append("super."); //$NON-NLS-1$ + getChildNode(node, SuperFieldAccess.NAME_PROPERTY).accept(this); + return false; + } + + /* + * @see ASTVisitor#visit(SuperMethodInvocation) + */ + public boolean visit(SuperMethodInvocation node) { + ASTNode qualifier= getChildNode(node, SuperMethodInvocation.QUALIFIER_PROPERTY); + if (qualifier != null) { + qualifier.accept(this); + this.result.append('.'); + } + this.result.append("super."); //$NON-NLS-1$ + if (node.getAST().apiLevel() >= AST.JLS3) { + visitList(node, SuperMethodInvocation.TYPE_ARGUMENTS_PROPERTY, String.valueOf(','), String.valueOf('<'), String.valueOf('>')); + } + getChildNode(node, SuperMethodInvocation.NAME_PROPERTY).accept(this); + this.result.append('('); + visitList(node, SuperMethodInvocation.ARGUMENTS_PROPERTY, String.valueOf(',')); + this.result.append(')'); + return false; + } + + /* + * @see ASTVisitor#visit(SwitchCase) + */ + public boolean visit(SwitchCase node) { + ASTNode expression= getChildNode(node, SwitchCase.EXPRESSION_PROPERTY); + if (expression == null) { + this.result.append("default"); //$NON-NLS-1$ + } else { + this.result.append("case "); //$NON-NLS-1$ + expression.accept(this); + } + this.result.append(':'); + return false; + } + + /* + * @see ASTVisitor#visit(SwitchStatement) + */ + public boolean visit(SwitchStatement node) { + this.result.append("switch ("); //$NON-NLS-1$ + getChildNode(node, SwitchStatement.EXPRESSION_PROPERTY).accept(this); + this.result.append(')'); + this.result.append('{'); + visitList(node, SwitchStatement.STATEMENTS_PROPERTY, null); + this.result.append('}'); + return false; + } + + /* + * @see ASTVisitor#visit(SynchronizedStatement) + */ + public boolean visit(SynchronizedStatement node) { + this.result.append("synchronized ("); //$NON-NLS-1$ + getChildNode(node, SynchronizedStatement.EXPRESSION_PROPERTY).accept(this); + this.result.append(')'); + getChildNode(node, SynchronizedStatement.BODY_PROPERTY).accept(this); + return false; + } + + /* + * @see ASTVisitor#visit(ThisExpression) + */ + public boolean visit(ThisExpression node) { + ASTNode qualifier= getChildNode(node, ThisExpression.QUALIFIER_PROPERTY); + if (qualifier != null) { + qualifier.accept(this); + this.result.append('.'); + } + this.result.append("this"); //$NON-NLS-1$ + return false; + } + + /* + * @see ASTVisitor#visit(ThrowStatement) + */ + public boolean visit(ThrowStatement node) { + this.result.append("throw "); //$NON-NLS-1$ + getChildNode(node, ThrowStatement.EXPRESSION_PROPERTY).accept(this); + this.result.append(';'); + return false; + } + + /* + * @see ASTVisitor#visit(TryStatement) + */ + public boolean visit(TryStatement node) { + this.result.append("try "); //$NON-NLS-1$ + getChildNode(node, TryStatement.BODY_PROPERTY).accept(this); + this.result.append(' '); + visitList(node, TryStatement.CATCH_CLAUSES_PROPERTY, null); + ASTNode finallyClause= getChildNode(node, TryStatement.FINALLY_PROPERTY); + if (finallyClause != null) { + this.result.append(" finally "); //$NON-NLS-1$ + finallyClause.accept(this); + } + return false; + } + + /* + * @see ASTVisitor#visit(TypeDeclaration) + */ + public boolean visit(TypeDeclaration node) { + int apiLevel= node.getAST().apiLevel(); + + ASTNode javadoc= getChildNode(node, TypeDeclaration.JAVADOC_PROPERTY); + if (javadoc != null) { + javadoc.accept(this); + } + + if (apiLevel == JLS2_INTERNAL) { + printModifiers(getIntAttribute(node, TypeDeclaration.MODIFIERS_PROPERTY), this.result); + } else { + visitList(node, TypeDeclaration.MODIFIERS2_PROPERTY, String.valueOf(' '), Util.EMPTY_STRING, String.valueOf(' ')); + } + + boolean isInterface= getBooleanAttribute(node, TypeDeclaration.INTERFACE_PROPERTY); + this.result.append(isInterface ? "interface " : "class "); //$NON-NLS-1$ //$NON-NLS-2$ + getChildNode(node, TypeDeclaration.NAME_PROPERTY).accept(this); + if (apiLevel >= AST.JLS3) { + visitList(node, TypeDeclaration.TYPE_PARAMETERS_PROPERTY, String.valueOf(','), String.valueOf('<'), String.valueOf('>')); + } + + this.result.append(' '); + + ChildPropertyDescriptor superClassProperty= (apiLevel == JLS2_INTERNAL) ? TypeDeclaration.SUPERCLASS_PROPERTY : TypeDeclaration.SUPERCLASS_TYPE_PROPERTY; + ASTNode superclass= getChildNode(node, superClassProperty); + if (superclass != null) { + this.result.append("extends "); //$NON-NLS-1$ + superclass.accept(this); + this.result.append(' '); + } + + ChildListPropertyDescriptor superInterfaceProperty= (apiLevel == JLS2_INTERNAL) ? TypeDeclaration.SUPER_INTERFACES_PROPERTY : TypeDeclaration.SUPER_INTERFACE_TYPES_PROPERTY; + String lead= isInterface ? "extends " : "implements "; //$NON-NLS-1$//$NON-NLS-2$ + visitList(node, superInterfaceProperty, String.valueOf(','), lead, Util.EMPTY_STRING); +//{ObjectTeams: predicate + ASTNode guardPredicate = getChildNode(node, TypeDeclaration.GUARD_PROPERTY); + if (guardPredicate != null) { + guardPredicate.accept(this); + this.result.append(' '); + } +// SH} + this.result.append('{'); + visitList(node, TypeDeclaration.BODY_DECLARATIONS_PROPERTY, null); +//{ObjectTeams: precedence + visitList(node, TypeDeclaration.PRECEDENCE_PROPERTY, null); +// SH} + this.result.append('}'); + return false; + } + + /* + * @see ASTVisitor#visit(TypeDeclarationStatement) + */ + public boolean visit(TypeDeclarationStatement node) { + if (node.getAST().apiLevel() == JLS2_INTERNAL) { + getChildNode(node, TypeDeclarationStatement.TYPE_DECLARATION_PROPERTY).accept(this); + } else { + getChildNode(node, TypeDeclarationStatement.DECLARATION_PROPERTY).accept(this); + } + return false; + } + + /* + * @see ASTVisitor#visit(TypeLiteral) + */ + public boolean visit(TypeLiteral node) { + getChildNode(node, TypeLiteral.TYPE_PROPERTY).accept(this); + this.result.append(".class"); //$NON-NLS-1$ + return false; + } + + /* + * @see ASTVisitor#visit(VariableDeclarationExpression) + */ + public boolean visit(VariableDeclarationExpression node) { + if (node.getAST().apiLevel() == JLS2_INTERNAL) { + printModifiers(getIntAttribute(node, VariableDeclarationExpression.MODIFIERS_PROPERTY), this.result); + } else { + visitList(node, VariableDeclarationExpression.MODIFIERS2_PROPERTY, String.valueOf(' '), Util.EMPTY_STRING, String.valueOf(' ')); + } + getChildNode(node, VariableDeclarationExpression.TYPE_PROPERTY).accept(this); + this.result.append(' '); + visitList(node, VariableDeclarationExpression.FRAGMENTS_PROPERTY, String.valueOf(',')); + return false; + } + + /* + * @see ASTVisitor#visit(VariableDeclarationFragment) + */ + public boolean visit(VariableDeclarationFragment node) { + getChildNode(node, VariableDeclarationFragment.NAME_PROPERTY).accept(this); + int extraDimensions= getIntAttribute(node, VariableDeclarationFragment.EXTRA_DIMENSIONS_PROPERTY); + for (int i = 0; i < extraDimensions; i++) { + this.result.append("[]"); //$NON-NLS-1$ + } + ASTNode initializer= getChildNode(node, VariableDeclarationFragment.INITIALIZER_PROPERTY); + if (initializer != null) { + this.result.append('='); + initializer.accept(this); + } + return false; + } + + /* + * @see ASTVisitor#visit(VariableDeclarationStatement) + */ + public boolean visit(VariableDeclarationStatement node) { + if (node.getAST().apiLevel() == JLS2_INTERNAL) { + printModifiers(getIntAttribute(node, VariableDeclarationStatement.MODIFIERS_PROPERTY), this.result); + } else { + visitList(node, VariableDeclarationStatement.MODIFIERS2_PROPERTY, String.valueOf(' '), Util.EMPTY_STRING, String.valueOf(' ')); + } + getChildNode(node, VariableDeclarationStatement.TYPE_PROPERTY).accept(this); + this.result.append(' '); + visitList(node, VariableDeclarationStatement.FRAGMENTS_PROPERTY, String.valueOf(',')); + this.result.append(';'); + return false; + } + + /* + * @see ASTVisitor#visit(WhileStatement) + */ + public boolean visit(WhileStatement node) { + this.result.append("while ("); //$NON-NLS-1$ + getChildNode(node, WhileStatement.EXPRESSION_PROPERTY).accept(this); + this.result.append(')'); + getChildNode(node, WhileStatement.BODY_PROPERTY).accept(this); + return false; + } + + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.BlockComment) + */ + public boolean visit(BlockComment node) { + return false; // cant flatten, needs source + } + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.LineComment) + */ + public boolean visit(LineComment node) { + return false; // cant flatten, needs source + } + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.MemberRef) + */ + public boolean visit(MemberRef node) { + ASTNode qualifier= getChildNode(node, MemberRef.QUALIFIER_PROPERTY); + if (qualifier != null) { + qualifier.accept(this); + } + this.result.append('#'); + getChildNode(node, MemberRef.NAME_PROPERTY).accept(this); + return false; + } + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.MethodRef) + */ + public boolean visit(MethodRef node) { + ASTNode qualifier= getChildNode(node, MethodRef.QUALIFIER_PROPERTY); + if (qualifier != null) { + qualifier.accept(this); + } + this.result.append('#'); + getChildNode(node, MethodRef.NAME_PROPERTY).accept(this); + this.result.append('('); + visitList(node, MethodRef.PARAMETERS_PROPERTY, ","); //$NON-NLS-1$ + this.result.append(')'); + return false; + } + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.MethodRefParameter) + */ + public boolean visit(MethodRefParameter node) { + getChildNode(node, MethodRefParameter.TYPE_PROPERTY).accept(this); + if (node.getAST().apiLevel() >= AST.JLS3) { + if (getBooleanAttribute(node, MethodRefParameter.VARARGS_PROPERTY)) { + this.result.append("..."); //$NON-NLS-1$ + } + } + ASTNode name= getChildNode(node, MethodRefParameter.NAME_PROPERTY); + if (name != null) { + this.result.append(' '); + name.accept(this); + } + return false; + } + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.TagElement) + */ + public boolean visit(TagElement node) { + Object tagName= getAttribute(node, TagElement.TAG_NAME_PROPERTY); + if (tagName != null) { + this.result.append((String) tagName); + } + List list= getChildList(node, TagElement.FRAGMENTS_PROPERTY); + for (int i= 0; i < list.size(); i++) { + if (i > 0 || tagName != null) { + this.result.append(' '); + } + ASTNode curr= (ASTNode) list.get(i); + if (curr instanceof TagElement) { + this.result.append('{'); + curr.accept(this); + this.result.append('}'); + } else { + curr.accept(this); + } + } + return false; + } + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.TextElement) + */ + public boolean visit(TextElement node) { + this.result.append(getAttribute(node, TextElement.TEXT_PROPERTY)); + return false; + } + /* + * @see ASTVisitor#visit(AnnotationTypeDeclaration) + * @since 3.0 + */ + public boolean visit(AnnotationTypeDeclaration node) { + ASTNode javadoc= getChildNode(node, AnnotationTypeDeclaration.JAVADOC_PROPERTY); + if (javadoc != null) { + javadoc.accept(this); + } + visitList(node, AnnotationTypeDeclaration.MODIFIERS2_PROPERTY, String.valueOf(' '), Util.EMPTY_STRING, String.valueOf(' ')); + this.result.append("@interface ");//$NON-NLS-1$ + getChildNode(node, AnnotationTypeDeclaration.NAME_PROPERTY).accept(this); + this.result.append('{'); + visitList(node, AnnotationTypeDeclaration.BODY_DECLARATIONS_PROPERTY, Util.EMPTY_STRING); + this.result.append('}'); + return false; + } + + /* + * @see ASTVisitor#visit(AnnotationTypeMemberDeclaration) + * @since 3.0 + */ + public boolean visit(AnnotationTypeMemberDeclaration node) { + ASTNode javadoc= getChildNode(node, AnnotationTypeMemberDeclaration.JAVADOC_PROPERTY); + if (javadoc != null) { + javadoc.accept(this); + } + visitList(node, AnnotationTypeMemberDeclaration.MODIFIERS2_PROPERTY, String.valueOf(' '), Util.EMPTY_STRING, String.valueOf(' ')); + getChildNode(node, AnnotationTypeMemberDeclaration.TYPE_PROPERTY).accept(this); + this.result.append(' '); + getChildNode(node, AnnotationTypeMemberDeclaration.NAME_PROPERTY).accept(this); + this.result.append("()");//$NON-NLS-1$ + ASTNode def= getChildNode(node, AnnotationTypeMemberDeclaration.DEFAULT_PROPERTY); + if (def != null) { + this.result.append(" default ");//$NON-NLS-1$ + def.accept(this); + } + this.result.append(';'); + return false; + } + + /* + * @see ASTVisitor#visit(EnhancedForStatement) + * @since 3.0 + */ + public boolean visit(EnhancedForStatement node) { + this.result.append("for (");//$NON-NLS-1$ + getChildNode(node, EnhancedForStatement.PARAMETER_PROPERTY).accept(this); + this.result.append(':'); + getChildNode(node, EnhancedForStatement.EXPRESSION_PROPERTY).accept(this); + this.result.append(')'); + getChildNode(node, EnhancedForStatement.BODY_PROPERTY).accept(this); + return false; + } + + /* + * @see ASTVisitor#visit(EnumConstantDeclaration) + * @since 3.0 + */ + public boolean visit(EnumConstantDeclaration node) { + ASTNode javadoc= getChildNode(node, EnumConstantDeclaration.JAVADOC_PROPERTY); + if (javadoc != null) { + javadoc.accept(this); + } + visitList(node, EnumConstantDeclaration.MODIFIERS2_PROPERTY, String.valueOf(' '), Util.EMPTY_STRING, String.valueOf(' ')); + getChildNode(node, EnumConstantDeclaration.NAME_PROPERTY).accept(this); + visitList(node, EnumConstantDeclaration.ARGUMENTS_PROPERTY, String.valueOf(','), String.valueOf('('), String.valueOf(')')); + ASTNode classDecl= getChildNode(node, EnumConstantDeclaration.ANONYMOUS_CLASS_DECLARATION_PROPERTY); + if (classDecl != null) { + classDecl.accept(this); + } + return false; + } + + /* + * @see ASTVisitor#visit(EnumDeclaration) + * @since 3.0 + */ + public boolean visit(EnumDeclaration node) { + ASTNode javadoc= getChildNode(node, EnumDeclaration.JAVADOC_PROPERTY); + if (javadoc != null) { + javadoc.accept(this); + } + visitList(node, EnumDeclaration.MODIFIERS2_PROPERTY, String.valueOf(' '), Util.EMPTY_STRING, String.valueOf(' ')); + this.result.append("enum ");//$NON-NLS-1$ + getChildNode(node, EnumDeclaration.NAME_PROPERTY).accept(this); + this.result.append(' '); + visitList(node, EnumDeclaration.SUPER_INTERFACE_TYPES_PROPERTY, String.valueOf(','), "implements ", Util.EMPTY_STRING); //$NON-NLS-1$ + + this.result.append('{'); + visitList(node, EnumDeclaration.ENUM_CONSTANTS_PROPERTY, String.valueOf(','), Util.EMPTY_STRING, Util.EMPTY_STRING); + visitList(node, EnumDeclaration.BODY_DECLARATIONS_PROPERTY, Util.EMPTY_STRING, String.valueOf(';'), Util.EMPTY_STRING); + this.result.append('}'); + return false; + } + /* + * @see ASTVisitor#visit(MarkerAnnotation) + * @since 3.0 + */ + public boolean visit(MarkerAnnotation node) { + this.result.append('@'); + getChildNode(node, MarkerAnnotation.TYPE_NAME_PROPERTY).accept(this); + return false; + } + + /* + * @see ASTVisitor#visit(MemberValuePair) + * @since 3.0 + */ + public boolean visit(MemberValuePair node) { + getChildNode(node, MemberValuePair.NAME_PROPERTY).accept(this); + this.result.append('='); + getChildNode(node, MemberValuePair.VALUE_PROPERTY).accept(this); + return false; + } + /* + * @see ASTVisitor#visit(Modifier) + * @since 3.0 + */ + public boolean visit(Modifier node) { + this.result.append(getAttribute(node, Modifier.KEYWORD_PROPERTY).toString()); + return false; + } + + /* + * @see ASTVisitor#visit(NormalAnnotation) + * @since 3.0 + */ + public boolean visit(NormalAnnotation node) { + this.result.append('@'); + getChildNode(node, NormalAnnotation.TYPE_NAME_PROPERTY).accept(this); + this.result.append('('); + visitList(node, NormalAnnotation.VALUES_PROPERTY, ", "); //$NON-NLS-1$ + this.result.append(')'); + return false; + } + /* + * @see ASTVisitor#visit(ParameterizedType) + * @since 3.0 + */ + public boolean visit(ParameterizedType node) { + getChildNode(node, ParameterizedType.TYPE_PROPERTY).accept(this); + this.result.append('<'); + visitList(node, ParameterizedType.TYPE_ARGUMENTS_PROPERTY, ", "); //$NON-NLS-1$ + this.result.append('>'); + return false; + } + + /* + * @see ASTVisitor#visit(QualifiedType) + * @since 3.0 + */ + public boolean visit(QualifiedType node) { + getChildNode(node, QualifiedType.QUALIFIER_PROPERTY).accept(this); + this.result.append('.'); + getChildNode(node, QualifiedType.NAME_PROPERTY).accept(this); + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.SingleMemberAnnotation) + */ + public boolean visit(SingleMemberAnnotation node) { + this.result.append('@'); + getChildNode(node, SingleMemberAnnotation.TYPE_NAME_PROPERTY).accept(this); + this.result.append('('); + getChildNode(node, SingleMemberAnnotation.VALUE_PROPERTY).accept(this); + this.result.append(')'); + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.TypeParameter) + */ + public boolean visit(TypeParameter node) { + getChildNode(node, TypeParameter.NAME_PROPERTY).accept(this); +//{ObjectTeams: <B base R>: + if (node.hasBaseBound()) + visitList(node, TypeParameter.TYPE_BOUNDS_PROPERTY, " & ", " base ", Util.EMPTY_STRING); //$NON-NLS-1$ //$NON-NLS-2$ + else +// SH} + visitList(node, TypeParameter.TYPE_BOUNDS_PROPERTY, " & ", " extends ", Util.EMPTY_STRING); //$NON-NLS-1$ //$NON-NLS-2$ + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.WildcardType) + */ + public boolean visit(WildcardType node) { + this.result.append('?'); + ASTNode bound = getChildNode(node, WildcardType.BOUND_PROPERTY); + if (bound != null) { + if (getBooleanAttribute(node, WildcardType.UPPER_BOUND_PROPERTY)) { + this.result.append(" extends ");//$NON-NLS-1$ + } else { + this.result.append(" super ");//$NON-NLS-1$ + } + bound.accept(this); + } + return false; + } +//{ObjectTeams: visit methods for OT-specific types + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.FieldAccessSpec) + */ + public boolean visit(FieldAccessSpec node) + { + if (node.hasSignature()) + { + getChildNode(node, FieldAccessSpec.FIELD_TYPE_PROPERTY).accept(this); + this.result.append(' '); + } + + getChildNode(node, FieldAccessSpec.NAME_PROPERTY).accept(this); + + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.MethodSpec) + */ + public boolean visit(MethodSpec node) + { + if (node.hasSignature()) + { + if(node.getAST().apiLevel() == AST.JLS3) { + visitList(node, MethodSpec.TYPE_PARAMETERS_PROPERTY, String.valueOf(','), String.valueOf('<'), " >"); //$NON-NLS-1$ + getChildNode(node, MethodSpec.RETURN_TYPE2_PROPERTY).accept(this); + } else { + getChildNode(node, MethodSpec.RETURN_TYPE_PROPERTY).accept(this); + } + if (getBooleanAttribute(node, MethodSpec.COVARIANT_RETURN_PROPERTY)) + this.result.append('+'); + this.result.append(' '); + } + + getChildNode(node, MethodSpec.NAME_PROPERTY).accept(this); + + if (node.hasSignature()) + { + this.result.append('('); + visitList(node, MethodSpec.PARAMETERS_PROPERTY, ", "); //$NON-NLS-1$ + this.result.append(')'); + } + + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.CalloutMappingDeclaration) + */ + @SuppressWarnings("nls") + public boolean visit(CalloutMappingDeclaration node) + { + ASTNode javadoc= getChildNode(node, CalloutMappingDeclaration.JAVADOC_PROPERTY); + if (javadoc != null) { + javadoc.accept(this); + } + + visitList(node, CalloutMappingDeclaration.MODIFIERS2_PROPERTY, String.valueOf(' '), Util.EMPTY_STRING, String.valueOf(' ')); + + ASTNode roleMappingElement = getChildNode(node, CalloutMappingDeclaration.ROLE_MAPPING_ELEMENT_PROPERTY); + ASTNode baseMappingElement = getChildNode(node, CalloutMappingDeclaration.BASE_MAPPING_ELEMENT_PROPERTY); + + if (roleMappingElement != null + && baseMappingElement != null) + { + roleMappingElement.accept(this); + this.result.append(' '); + node.bindingOperator().accept(this); + this.result.append(' '); + baseMappingElement.accept(this); + } + else + { + node.setFlags(ASTNode.MALFORMED); + } + + if (!node.getParameterMappings().isEmpty()) + { + this.result.append(" with {\n "); + visitList(node, CalloutMappingDeclaration.PARAMETER_MAPPINGS_PROPERTY, ",\n "); + this.result.append("\n}"); + } + else + { + this.result.append(';'); + } + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.CallinMappingDeclaration) + */ + @SuppressWarnings({ "nls", "rawtypes" }) + public boolean visit(CallinMappingDeclaration node) + { + ASTNode javadoc = getChildNode(node, CallinMappingDeclaration.JAVADOC_PROPERTY); + if (javadoc != null) { + javadoc.accept(this); + } + + ASTNode roleMappingElement = getChildNode(node, CallinMappingDeclaration.ROLE_MAPPING_ELEMENT_PROPERTY); + List baseMappingElement = getChildList(node, CallinMappingDeclaration.BASE_MAPPING_ELEMENTS_PROPERTY); + + if ( roleMappingElement != null + && baseMappingElement != null) + { + SimpleName nameNode = (SimpleName)getChildNode(node, CallinMappingDeclaration.NAME_PROPERTY); + if (nameNode != null && nameNode.getIdentifier().charAt(0) != '<') { + nameNode.accept(this); + this.result.append(": "); + } + roleMappingElement.accept(this); + this.result.append(' '); + MethodBindingOperator bindingOperator = (MethodBindingOperator)getAttribute(node, CallinMappingDeclaration.BINDING_OPERATOR_PROPERTY); + bindingOperator.accept(this); + this.result.append(' '); + + visitList(node, CallinMappingDeclaration.BASE_MAPPING_ELEMENTS_PROPERTY, String.valueOf(',')); + } + else + { + node.setFlags(ASTNode.MALFORMED); + } + + ASTNode guardPredicate = getChildNode(node, CallinMappingDeclaration.GUARD_PROPERTY); + if (guardPredicate != null) { + this.result.append(' '); + guardPredicate.accept(this); + } + + if (!node.getParameterMappings().isEmpty()) + { + this.result.append(" with {\n "); + visitList(node, CallinMappingDeclaration.PARAMETER_MAPPINGS_PROPERTY, ",\n "); + this.result.append("\n}"); + } + else + { + this.result.append(';'); + } + + return false; + } + + public boolean visit(MethodBindingOperator node) { + switch(node.getBindingKind()) { + case MethodBindingOperator.KIND_CALLIN: this.result.append(CallinMappingDeclaration.CALLIN); break; + case MethodBindingOperator.KIND_CALLOUT: this.result.append(CalloutMappingDeclaration.CALLOUT); break; + case MethodBindingOperator.KIND_CALLOUT_OVERRIDE: this.result.append(CalloutMappingDeclaration.CALLOUT_OVERRIDE); break; + } + Modifier modifier = node.bindingModifier(); + if (modifier != null) { + this.result.append(' '); + modifier.accept(this); + } else if (node.getBindingKind() == MethodBindingOperator.KIND_CALLIN) { + this.result.append("<missing callin modifier>"); //$NON-NLS-1$ + } + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.LiftingType) + */ + public boolean visit(LiftingType node) + { + getChildNode(node, LiftingType.BASE_TYPE_PROPERTY).accept(this); + this.result.append(' '); + this.result.append("as"); //$NON-NLS-1$ + this.result.append(' '); + getChildNode(node, LiftingType.ROLE_TYPE_PROPERTY).accept(this); + + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.TypeAnchor) + */ + public boolean visit(TypeAnchor node) + { + this.result.append('@'); + getChildNode(node, TypeAnchor.PATH_PROPERTY).accept(this); + + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.WithinStatement) + */ + @SuppressWarnings("nls") + public boolean visit(WithinStatement node) + { + this.result.append("within("); + getChildNode(node, WithinStatement.TEAM_EXPRESSION_PROPERTY).accept(this); + this.result.append(") "); + getChildNode(node, WithinStatement.BODY_PROPERTY).accept(this); + + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.TSuperMessageSend) + */ + public boolean visit(TSuperMessageSend node) + { + ASTNode qualifier = getChildNode(node, TSuperMessageSend.QUALIFIER_PROPERTY); + if (qualifier != null) { + qualifier.accept(this); + this.result.append('.'); + } + this.result.append("tsuper."); //$NON-NLS-1$ + getChildNode(node, TSuperMessageSend.NAME_PROPERTY).accept(this); + this.result.append('('); + visitList(node, TSuperMessageSend.ARGUMENTS_PROPERTY, String.valueOf(',')); + this.result.append(')'); + this.result.append(';'); + + + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.TSuperConstructorInvocation) + */ + public boolean visit(TSuperConstructorInvocation node) + { + this.result.append("tsuper"); //$NON-NLS-1$ + this.result.append('('); + visitList(node, TSuperConstructorInvocation.ARGUMENTS_PROPERTY, String.valueOf(',')); + this.result.append(')'); + this.result.append(';'); + + return false; + } + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.BaseCallMessageSend) + */ + public boolean visit(BaseCallMessageSend node) + { + this.result.append("base."); //$NON-NLS-1$ + getChildNode(node, BaseCallMessageSend.NAME_PROPERTY).accept(this); + this.result.append('('); + visitList(node, BaseCallMessageSend.ARGUMENTS_PROPERTY, String.valueOf(',')); + this.result.append(')'); + + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.BaseConstructorMessageSend) + */ + public boolean visit(BaseConstructorInvocation node) + { + this.result.append("base"); //$NON-NLS-1$ + this.result.append('('); + visitList(node, BaseConstructorInvocation.ARGUMENTS_PROPERTY, String.valueOf(',')); + this.result.append(')'); + this.result.append(';'); + + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.ParameterMapping) + */ + @SuppressWarnings("nls") + public boolean visit(ParameterMapping node) + { + if (node.getExpression() != null) + { + if (node.getDirection().equals("->")) + { + getChildNode(node, ParameterMapping.EXPRESSION_PROPERTY).accept(this); + this.result.append(" "); + this.result.append(node.getDirection()); + this.result.append(" "); + this.result.append(node.getIdentifier()); + } + if (node.getDirection().equals("<-")) + { + this.result.append(node.getIdentifier()); + this.result.append(" "); + this.result.append(node.getDirection()); + this.result.append(" "); + getChildNode(node, ParameterMapping.EXPRESSION_PROPERTY).accept(this); + } + } + return false; + } + /* + * @see ASTVisitor#visit(RoleTypeDeclaration) + */ + public boolean visit(RoleTypeDeclaration node) + { + ASTNode javadoc= getChildNode(node, RoleTypeDeclaration.JAVADOC_PROPERTY); + if (javadoc != null) + { + javadoc.accept(this); + } + if (node.getAST().apiLevel() == JLS2_INTERNAL) { + printModifiers(getIntAttribute(node, RoleTypeDeclaration.MODIFIERS_PROPERTY), this.result); + } else { + visitList(node, RoleTypeDeclaration.MODIFIERS2_PROPERTY, String.valueOf(' '), Util.EMPTY_STRING, String.valueOf(' ')); + } + + this.result.append("class "); //$NON-NLS-1$ + getChildNode(node, RoleTypeDeclaration.NAME_PROPERTY).accept(this); + this.result.append(' '); + + ASTNode superclass = getChildNode(node, RoleTypeDeclaration.SUPERCLASS_TYPE_PROPERTY); + if (superclass != null) + { + this.result.append("extends "); //$NON-NLS-1$ + superclass.accept(this); + this.result.append(' '); + } + + String lead= "implements "; //$NON-NLS-1$ + visitList(node, RoleTypeDeclaration.SUPER_INTERFACE_TYPES_PROPERTY, String.valueOf(','), lead, Util.EMPTY_STRING); + + ASTNode baseClass = getChildNode(node, RoleTypeDeclaration.BASECLASS_TYPE_PROPERTY); + if (baseClass != null) + { + this.result.append("playedBy "); //$NON-NLS-1$ + baseClass.accept(this); + this.result.append(' '); + } + ASTNode guardPredicate = getChildNode(node, RoleTypeDeclaration.GUARD_PROPERTY); + if (guardPredicate != null) { + guardPredicate.accept(this); + this.result.append(' '); + } + + this.result.append('{'); + visitList(node, RoleTypeDeclaration.BODY_DECLARATIONS_PROPERTY, null); + visitList(node, RoleTypeDeclaration.PRECEDENCE_PROPERTY, null); + this.result.append('}'); + return false; + } + @SuppressWarnings("nls") + @Override + public boolean visit(GuardPredicateDeclaration guard) { + if (guard.isBase()) + this.result.append("base "); + this.result.append("when ("); + guard.getExpression().accept(this); + this.result.append(')'); + return false; + } + + @SuppressWarnings("nls") + @Override + public boolean visit(PrecedenceDeclaration node) { + this.result.append("precedence "); + String sep = ""; + for (Object element: node.elements()) { + this.result.append(sep); + ((ASTNode)element).accept(this); + sep = ", "; + } + this.result.append(';'); + return false; + } +// jsv+SH} +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteFormatter.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteFormatter.java new file mode 100644 index 000000000..b5e6b72ae --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteFormatter.java @@ -0,0 +1,595 @@ +/******************************************************************************* + * Copyright (c) 2000, 2009 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 + * $Id: ASTRewriteFormatter.java 22741 2009-10-13 22:23:05Z stephan $ + * + * Contributors: + * IBM Corporation - initial API and implementation + * Fraunhofer FIRST - extended API and implementation + * Technical University Berlin - extended API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.core.dom.rewrite; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Map; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.jdt.core.ToolFactory; +import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.Annotation; +import org.eclipse.jdt.core.dom.Block; +import org.eclipse.jdt.core.dom.BodyDeclaration; +import org.eclipse.jdt.core.dom.Expression; +import org.eclipse.jdt.core.dom.MethodDeclaration; +import org.eclipse.jdt.core.dom.Statement; +import org.eclipse.jdt.core.dom.TypeDeclaration; +import org.eclipse.jdt.core.formatter.CodeFormatter; +import org.eclipse.jdt.core.formatter.IndentManipulation; +import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; +import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.BadPositionCategoryException; +import org.eclipse.jface.text.DefaultPositionUpdater; +import org.eclipse.jface.text.Document; +import org.eclipse.jface.text.Position; +import org.eclipse.text.edits.DeleteEdit; +import org.eclipse.text.edits.InsertEdit; +import org.eclipse.text.edits.MultiTextEdit; +import org.eclipse.text.edits.ReplaceEdit; +import org.eclipse.text.edits.TextEdit; + +/* package */ final class ASTRewriteFormatter { + + public static class NodeMarker extends Position { + public Object data; + } + + private class ExtendedFlattener extends ASTRewriteFlattener { + + private ArrayList positions; + + public ExtendedFlattener(RewriteEventStore store) { + super(store); + this.positions= new ArrayList(); + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#preVisit(ASTNode) + */ + public void preVisit(ASTNode node) { + Object trackData= getEventStore().getTrackedNodeData(node); + if (trackData != null) { + addMarker(trackData, this.result.length(), 0); + } + Object placeholderData= getPlaceholders().getPlaceholderData(node); + if (placeholderData != null) { + addMarker(placeholderData, this.result.length(), 0); + } + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.core.dom.ASTVisitor#postVisit(ASTNode) + */ + public void postVisit(ASTNode node) { + Object placeholderData= getPlaceholders().getPlaceholderData(node); + if (placeholderData != null) { + fixupLength(placeholderData, this.result.length()); + } + Object trackData= getEventStore().getTrackedNodeData(node); + if (trackData != null) { + fixupLength(trackData, this.result.length()); + } + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.corext.dom.ASTRewriteFlattener#visit(org.eclipse.jdt.core.dom.Block) + */ + public boolean visit(Block node) { + if (getPlaceholders().isCollapsed(node)) { + visitList(node, Block.STATEMENTS_PROPERTY, null); + return false; + } + return super.visit(node); + } + + private NodeMarker addMarker(Object annotation, int startOffset, int length) { + NodeMarker marker= new NodeMarker(); + marker.offset= startOffset; + marker.length= length; + marker.data= annotation; + this.positions.add(marker); + return marker; + } + + private void fixupLength(Object data, int endOffset) { + for (int i= this.positions.size()-1; i >= 0 ; i--) { + NodeMarker marker= (NodeMarker) this.positions.get(i); + if (marker.data == data) { + marker.length= endOffset - marker.offset; + return; + } + } + } + + public NodeMarker[] getMarkers() { + return (NodeMarker[]) this.positions.toArray(new NodeMarker[this.positions.size()]); + } + } + + private final String lineDelimiter; + private final int tabWidth; + private final int indentWidth; + + private final NodeInfoStore placeholders; + private final RewriteEventStore eventStore; + + private final Map options; + + + public ASTRewriteFormatter(NodeInfoStore placeholders, RewriteEventStore eventStore, Map options, String lineDelimiter) { + this.placeholders= placeholders; + this.eventStore= eventStore; + + this.options= options; + this.lineDelimiter= lineDelimiter; + + this.tabWidth= IndentManipulation.getTabWidth(options); + this.indentWidth= IndentManipulation.getIndentWidth(options); + } + + + + public NodeInfoStore getPlaceholders() { + return this.placeholders; + } + + public RewriteEventStore getEventStore() { + return this.eventStore; + } + + public int getTabWidth() { + return this.tabWidth; + } + + public int getIndentWidth() { + return this.indentWidth; + } + + public String getLineDelimiter() { + return this.lineDelimiter; + } + + /** + * Returns the string accumulated in the visit formatted using the default formatter. + * Updates the existing node's positions. + * + * @param node The node to flatten. + * @param initialIndentationLevel The initial indentation level. + * @param resultingMarkers Resulting the updated NodeMarkers. + * @return Returns the serialized and formatted code. + */ + public String getFormattedResult(ASTNode node, int initialIndentationLevel, Collection resultingMarkers) { + + ExtendedFlattener flattener= new ExtendedFlattener(this.eventStore); + node.accept(flattener); + + NodeMarker[] markers= flattener.getMarkers(); + for (int i= 0; i < markers.length; i++) { + resultingMarkers.add(markers[i]); // add to result + } + + String unformatted= flattener.getResult(); + TextEdit edit= formatNode(node, unformatted, initialIndentationLevel); + if (edit == null) { + if (initialIndentationLevel > 0) { + // at least correct the indent + String indentString = createIndentString(initialIndentationLevel); + ReplaceEdit[] edits = IndentManipulation.getChangeIndentEdits(unformatted, 0, this.tabWidth, this.indentWidth, indentString); + edit= new MultiTextEdit(); + edit.addChild(new InsertEdit(0, indentString)); + edit.addChildren(edits); + } else { + return unformatted; + } + } + return evaluateFormatterEdit(unformatted, edit, markers); + } + + public String createIndentString(int indentationUnits) { + return ToolFactory.createCodeFormatter(this.options).createIndentationString(indentationUnits); + } + + public String getIndentString(String currentLine) { + return IndentManipulation.extractIndentString(currentLine, this.tabWidth, this.indentWidth); + } + + public String changeIndent(String code, int codeIndentLevel, String newIndent) { + return IndentManipulation.changeIndent(code, codeIndentLevel, this.tabWidth, this.indentWidth, newIndent, this.lineDelimiter); + } + + public int computeIndentUnits(String line) { + return IndentManipulation.measureIndentUnits(line, this.tabWidth, this.indentWidth); + } + + /** + * Evaluates the edit on the given string. + * @param string The string to format + * @param edit The edit resulted from the code formatter + * @param positions Positions to update or <code>null</code>. + * @return The formatted string + * @throws IllegalArgumentException If the positions are not inside the string, a + * IllegalArgumentException is thrown. + */ + public static String evaluateFormatterEdit(String string, TextEdit edit, Position[] positions) { + try { + Document doc= createDocument(string, positions); + edit.apply(doc, 0); + if (positions != null) { + for (int i= 0; i < positions.length; i++) { + Assert.isTrue(!positions[i].isDeleted, "Position got deleted"); //$NON-NLS-1$ + } + } + return doc.get(); + } catch (BadLocationException e) { + //JavaPlugin.log(e); // bug in the formatter + Assert.isTrue(false, "Fromatter created edits with wrong positions: " + e.getMessage()); //$NON-NLS-1$ + } + return null; + } + + public TextEdit formatString(int kind, String string, int offset, int length, int indentationLevel) { + return ToolFactory.createCodeFormatter(this.options).format(kind, string, offset, length, indentationLevel, this.lineDelimiter); + } + + /** + * Creates edits that describe how to format the given string. Returns <code>null</code> if the code could not be formatted for the given kind. + * @param node Node describing the type of the string + * @param str The unformatted string + * @param indentationLevel + * @return Returns the edit representing the result of the formatter + * @throws IllegalArgumentException If the offset and length are not inside the string, a + * IllegalArgumentException is thrown. + */ + private TextEdit formatNode(ASTNode node, String str, int indentationLevel) { + int code; + String prefix= ""; //$NON-NLS-1$ + String suffix= ""; //$NON-NLS-1$ +//{ObjectTeams: check code flavour: + this.options.put(CompilerOptions.OPTION_AllowScopedKeywords, isOTJCode(node)?CompilerOptions.DISABLED:CompilerOptions.ENABLED); + // FIXME(SH): if not recognizable as OTJCode set OPTION_PureJavaOnly to ENABLED?? +// SH} + if (node instanceof Statement) { + code= CodeFormatter.K_STATEMENTS; + if (node.getNodeType() == ASTNode.SWITCH_CASE) { + prefix= "switch(1) {"; //$NON-NLS-1$ + suffix= "}"; //$NON-NLS-1$ + code= CodeFormatter.K_STATEMENTS; + } + } else if (node instanceof Expression && node.getNodeType() != ASTNode.VARIABLE_DECLARATION_EXPRESSION) { +//{ObjectTeams: tells the formatter to format a single parameter mapping. It is not handled by the formatExpression method !! + if (node.getNodeType() == ASTNode.PARAMETER_MAPPING) { + code = CodeFormatter.K_PARAMETER_MAPPING; + } else +//jsv} + if (node instanceof Annotation) { + suffix= "\nclass A {}"; //$NON-NLS-1$ + code= CodeFormatter.K_COMPILATION_UNIT; + } else { + code= CodeFormatter.K_EXPRESSION; + } + } else if (node instanceof BodyDeclaration) { + code= CodeFormatter.K_CLASS_BODY_DECLARATIONS; + } else { + switch (node.getNodeType()) { + case ASTNode.ARRAY_TYPE: + case ASTNode.PARAMETERIZED_TYPE: + case ASTNode.PRIMITIVE_TYPE: + case ASTNode.QUALIFIED_TYPE: + case ASTNode.SIMPLE_TYPE: + suffix= " x;"; //$NON-NLS-1$ + code= CodeFormatter.K_CLASS_BODY_DECLARATIONS; + break; + case ASTNode.WILDCARD_TYPE: + prefix= "A<"; //$NON-NLS-1$ + suffix= "> x;"; //$NON-NLS-1$ + code= CodeFormatter.K_CLASS_BODY_DECLARATIONS; + break; + case ASTNode.COMPILATION_UNIT: + code= CodeFormatter.K_COMPILATION_UNIT; + break; + case ASTNode.VARIABLE_DECLARATION_EXPRESSION: + case ASTNode.SINGLE_VARIABLE_DECLARATION: + suffix= ";"; //$NON-NLS-1$ + code= CodeFormatter.K_STATEMENTS; + break; + case ASTNode.VARIABLE_DECLARATION_FRAGMENT: + prefix= "A "; //$NON-NLS-1$ + suffix= ";"; //$NON-NLS-1$ + code= CodeFormatter.K_STATEMENTS; + break; + case ASTNode.PACKAGE_DECLARATION: + case ASTNode.IMPORT_DECLARATION: + suffix= "\nclass A {}"; //$NON-NLS-1$ + code= CodeFormatter.K_COMPILATION_UNIT; + break; + case ASTNode.JAVADOC: + suffix= "\nclass A {}"; //$NON-NLS-1$ + code= CodeFormatter.K_COMPILATION_UNIT; + break; + case ASTNode.CATCH_CLAUSE: + prefix= "try {}"; //$NON-NLS-1$ + code= CodeFormatter.K_STATEMENTS; + break; + case ASTNode.ANONYMOUS_CLASS_DECLARATION: + prefix= "new A()"; //$NON-NLS-1$ + suffix= ";"; //$NON-NLS-1$ + code= CodeFormatter.K_STATEMENTS; + break; + case ASTNode.MEMBER_VALUE_PAIR: + prefix= "@Author("; //$NON-NLS-1$ + suffix= ") class x {}"; //$NON-NLS-1$ + code= CodeFormatter.K_COMPILATION_UNIT; + break; + case ASTNode.MODIFIER: + suffix= " class x {}"; //$NON-NLS-1$ + code= CodeFormatter.K_COMPILATION_UNIT; + break; + case ASTNode.TYPE_PARAMETER: + prefix= "class X<"; //$NON-NLS-1$ + suffix= "> {}"; //$NON-NLS-1$ + code= CodeFormatter.K_COMPILATION_UNIT; + break; + case ASTNode.MEMBER_REF: + case ASTNode.METHOD_REF: + case ASTNode.METHOD_REF_PARAMETER: + case ASTNode.TAG_ELEMENT: + case ASTNode.TEXT_ELEMENT: + // javadoc formatting disabled due to bug 93644 + return null; + +// wiat for bug 93644 +// case ASTNode.MEMBER_REF: +// case ASTNode.METHOD_REF: +// prefix= "/**\n * @see "; +// suffix= "\n*/"; +// code= CodeFormatter.K_JAVA_DOC; +// break; +// case ASTNode.METHOD_REF_PARAMETER: +// prefix= "/**\n * @see A#foo("; +// suffix= ")\n*/"; +// code= CodeFormatter.K_JAVA_DOC; +// break; +// case ASTNode.TAG_ELEMENT: +// case ASTNode.TEXT_ELEMENT: +// prefix= "/**\n * "; +// suffix= "\n*/"; +// code= CodeFormatter.K_JAVA_DOC; +// break; + default: + //Assert.isTrue(false, "Node type not covered: " + node.getClass().getName()); + return null; + } + } + + String concatStr= prefix + str + suffix; + TextEdit edit= formatString(code, concatStr, prefix.length(), str.length(), indentationLevel); + + if (prefix.length() > 0) { + edit= shifEdit(edit, prefix.length()); + } + return edit; + } + +//{ObjectTeams: needed to configure the scanner: + private boolean isOTJCode(ASTNode node) { + while (node != null && node.getNodeType() != ASTNode.TYPE_DECLARATION) { + switch (node.getNodeType()) { + case ASTNode.ROLE_TYPE_DECLARATION: + case ASTNode.CALLOUT_MAPPING_DECLARATION: + case ASTNode.CALLIN_MAPPING_DECLARATION: + case ASTNode.PARAMETER_MAPPING: + return true; + case ASTNode.METHOD_DECLARATION: + if ((((MethodDeclaration)node).getModifiers() & ExtraCompilerModifiers.AccCallin) != 0) + return true; + } + node= node.getParent(); + } + if (node != null) { + TypeDeclaration type = (TypeDeclaration)node; + return type.isRole() || type.isTeam(); + } + return false; + } +// SH} + + private static TextEdit shifEdit(TextEdit oldEdit, int diff) { + TextEdit newEdit; + if (oldEdit instanceof ReplaceEdit) { + ReplaceEdit edit= (ReplaceEdit) oldEdit; + newEdit= new ReplaceEdit(edit.getOffset() - diff, edit.getLength(), edit.getText()); + } else if (oldEdit instanceof InsertEdit) { + InsertEdit edit= (InsertEdit) oldEdit; + newEdit= new InsertEdit(edit.getOffset() - diff, edit.getText()); + } else if (oldEdit instanceof DeleteEdit) { + DeleteEdit edit= (DeleteEdit) oldEdit; + newEdit= new DeleteEdit(edit.getOffset() - diff, edit.getLength()); + } else if (oldEdit instanceof MultiTextEdit) { + newEdit= new MultiTextEdit(); + } else { + return null; // not supported + } + TextEdit[] children= oldEdit.getChildren(); + for (int i= 0; i < children.length; i++) { + TextEdit shifted= shifEdit(children[i], diff); + if (shifted != null) { + newEdit.addChild(shifted); + } + } + return newEdit; + } + + private static Document createDocument(String string, Position[] positions) throws IllegalArgumentException { + Document doc= new Document(string); + try { + if (positions != null) { + final String POS_CATEGORY= "myCategory"; //$NON-NLS-1$ + + doc.addPositionCategory(POS_CATEGORY); + doc.addPositionUpdater(new DefaultPositionUpdater(POS_CATEGORY) { + protected boolean notDeleted() { + int start= this.fOffset; + int end= start + this.fLength; + if (start < this.fPosition.offset && (this.fPosition.offset + this.fPosition.length < end)) { + this.fPosition.offset= end; // deleted positions: set to end of remove + return false; + } + return true; + } + }); + for (int i= 0; i < positions.length; i++) { + try { + doc.addPosition(POS_CATEGORY, positions[i]); + } catch (BadLocationException e) { + throw new IllegalArgumentException("Position outside of string. offset: " + positions[i].offset + ", length: " + positions[i].length + ", string size: " + string.length()); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$ + } + } + } + } catch (BadPositionCategoryException cannotHappen) { + // can not happen: category is correctly set up + } + return doc; + } + + + + public static interface Prefix { + String getPrefix(int indent); + } + + public static interface BlockContext { + String[] getPrefixAndSuffix(int indent, ASTNode node, RewriteEventStore events); + } + + public static class ConstPrefix implements Prefix { + private String prefix; + + public ConstPrefix(String prefix) { + this.prefix= prefix; + } + + public String getPrefix(int indent) { + return this.prefix; + } + } + + private class FormattingPrefix implements Prefix { + private int kind; + private String string; + private int start; + private int length; + + public FormattingPrefix(String string, String sub, int kind) { + this.start= string.indexOf(sub); + this.length= sub.length(); + this.string= string; + this.kind= kind; + } + + public String getPrefix(int indent) { + Position pos= new Position(this.start, this.length); + String str= this.string; + TextEdit res= formatString(this.kind, str, 0, str.length(), indent); + if (res != null) { + str= evaluateFormatterEdit(str, res, new Position[] { pos }); + } + return str.substring(pos.offset + 1, pos.offset + pos.length - 1); + } + } + + private class BlockFormattingPrefix implements BlockContext { + private String prefix; + private int start; + + public BlockFormattingPrefix(String prefix, int start) { + this.start= start; + this.prefix= prefix; + } + + public String[] getPrefixAndSuffix(int indent, ASTNode node, RewriteEventStore events) { + String nodeString= ASTRewriteFlattener.asString(node, events); + String str= this.prefix + nodeString; + Position pos= new Position(this.start, this.prefix.length() + 1 - this.start); + + TextEdit res= formatString(CodeFormatter.K_STATEMENTS, str, 0, str.length(), indent); + if (res != null) { + str= evaluateFormatterEdit(str, res, new Position[] { pos }); + } + return new String[] { str.substring(pos.offset + 1, pos.offset + pos.length - 1), ""}; //$NON-NLS-1$ + } + } + + private class BlockFormattingPrefixSuffix implements BlockContext { + private String prefix; + private String suffix; + private int start; + + public BlockFormattingPrefixSuffix(String prefix, String suffix, int start) { + this.start= start; + this.suffix= suffix; + this.prefix= prefix; + } + + public String[] getPrefixAndSuffix(int indent, ASTNode node, RewriteEventStore events) { + String nodeString= ASTRewriteFlattener.asString(node, events); + int nodeStart= this.prefix.length(); + int nodeEnd= nodeStart + nodeString.length() - 1; + + String str= this.prefix + nodeString + this.suffix; + + Position pos1= new Position(this.start, nodeStart + 1 - this.start); + Position pos2= new Position(nodeEnd, 2); + + TextEdit res= formatString(CodeFormatter.K_STATEMENTS, str, 0, str.length(), indent); + if (res != null) { + str= evaluateFormatterEdit(str, res, new Position[] { pos1, pos2 }); + } + return new String[] { + str.substring(pos1.offset + 1, pos1.offset + pos1.length - 1), + str.substring(pos2.offset + 1, pos2.offset + pos2.length - 1) + }; + } + } + + public final static Prefix NONE= new ConstPrefix(""); //$NON-NLS-1$ + public final static Prefix SPACE= new ConstPrefix(" "); //$NON-NLS-1$ + public final static Prefix ASSERT_COMMENT= new ConstPrefix(" : "); //$NON-NLS-1$ + + public final Prefix VAR_INITIALIZER= new FormattingPrefix("A a={};", "a={" , CodeFormatter.K_STATEMENTS); //$NON-NLS-1$ //$NON-NLS-2$ + public final Prefix METHOD_BODY= new FormattingPrefix("void a() {}", ") {" , CodeFormatter.K_CLASS_BODY_DECLARATIONS); //$NON-NLS-1$ //$NON-NLS-2$ + public final Prefix FINALLY_BLOCK= new FormattingPrefix("try {} finally {}", "} finally {", CodeFormatter.K_STATEMENTS); //$NON-NLS-1$ //$NON-NLS-2$ + public final Prefix CATCH_BLOCK= new FormattingPrefix("try {} catch(Exception e) {}", "} c" , CodeFormatter.K_STATEMENTS); //$NON-NLS-1$ //$NON-NLS-2$ + public final Prefix ANNOT_MEMBER_DEFAULT= new FormattingPrefix("String value() default 1;", ") default 1" , CodeFormatter.K_CLASS_BODY_DECLARATIONS); //$NON-NLS-1$ //$NON-NLS-2$ + public final Prefix ENUM_BODY_START= new FormattingPrefix("enum E { A(){void foo(){}} }", "){v" , CodeFormatter.K_COMPILATION_UNIT); //$NON-NLS-1$ //$NON-NLS-2$ + public final Prefix ENUM_BODY_END= new FormattingPrefix("enum E { A(){void foo(){ }}, B}", "}}," , CodeFormatter.K_COMPILATION_UNIT); //$NON-NLS-1$ //$NON-NLS-2$ + public final Prefix WILDCARD_EXTENDS= new FormattingPrefix("A<? extends B> a;", "? extends B" , CodeFormatter.K_CLASS_BODY_DECLARATIONS); //$NON-NLS-1$ //$NON-NLS-2$ + public final Prefix WILDCARD_SUPER= new FormattingPrefix("A<? super B> a;", "? super B" , CodeFormatter.K_CLASS_BODY_DECLARATIONS); //$NON-NLS-1$ //$NON-NLS-2$ + + public final Prefix FIRST_ENUM_CONST= new FormattingPrefix("enum E { X;}", "{ X" , CodeFormatter.K_COMPILATION_UNIT); //$NON-NLS-1$ //$NON-NLS-2$ + public final Prefix ANNOTATION_SEPARATION= new FormattingPrefix("@A @B class C {}", "A @" , CodeFormatter.K_COMPILATION_UNIT); //$NON-NLS-1$ //$NON-NLS-2$ + public final Prefix PARAM_ANNOTATION_SEPARATION= new FormattingPrefix("void foo(@A @B p) { }", "A @" , CodeFormatter.K_CLASS_BODY_DECLARATIONS); //$NON-NLS-1$ //$NON-NLS-2$ + + public final BlockContext IF_BLOCK_WITH_ELSE= new BlockFormattingPrefixSuffix("if (true)", "else{}", 8); //$NON-NLS-1$ //$NON-NLS-2$ + public final BlockContext IF_BLOCK_NO_ELSE= new BlockFormattingPrefix("if (true)", 8); //$NON-NLS-1$ + public final BlockContext ELSE_AFTER_STATEMENT= new BlockFormattingPrefix("if (true) foo(); else ", 15); //$NON-NLS-1$ + public final BlockContext ELSE_AFTER_BLOCK= new BlockFormattingPrefix("if (true) {} else ", 11); //$NON-NLS-1$ + + public final BlockContext FOR_BLOCK= new BlockFormattingPrefix("for (;;) ", 7); //$NON-NLS-1$ + public final BlockContext WHILE_BLOCK= new BlockFormattingPrefix("while (true)", 11); //$NON-NLS-1$ + public final BlockContext DO_BLOCK= new BlockFormattingPrefixSuffix("do ", "while (true);", 1); //$NON-NLS-1$ //$NON-NLS-2$ + +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ImportRewriteAnalyzer.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ImportRewriteAnalyzer.java new file mode 100644 index 000000000..923de4bef --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ImportRewriteAnalyzer.java @@ -0,0 +1,1189 @@ +/******************************************************************************* + * Copyright (c) 2000, 2010 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: + * IBM Corporation - initial API and implementation + * Technical University Berlin - extended API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.core.dom.rewrite; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.jdt.core.IBuffer; +import org.eclipse.jdt.core.ICompilationUnit; +import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.core.Signature; +import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.ImportDeclaration; +import org.eclipse.jdt.core.dom.PackageDeclaration; +import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants; +import org.eclipse.jdt.core.search.IJavaSearchConstants; +import org.eclipse.jdt.core.search.IJavaSearchScope; +import org.eclipse.jdt.core.search.SearchEngine; +import org.eclipse.jdt.core.search.TypeNameRequestor; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.Region; +import org.eclipse.text.edits.DeleteEdit; +import org.eclipse.text.edits.InsertEdit; +import org.eclipse.text.edits.MultiTextEdit; + +@SuppressWarnings("unchecked") +public final class ImportRewriteAnalyzer { + + private final ICompilationUnit compilationUnit; + private final ArrayList packageEntries; + + private final List importsCreated; + private final List staticImportsCreated; + + private final IRegion replaceRange; + + private final int importOnDemandThreshold; + private final int staticImportOnDemandThreshold; + + private boolean filterImplicitImports; + private boolean findAmbiguousImports; + + private int flags= 0; + + private static final int F_NEEDS_LEADING_DELIM= 2; + private static final int F_NEEDS_TRAILING_DELIM= 4; + + private static final String JAVA_LANG= "java.lang"; //$NON-NLS-1$ + + public ImportRewriteAnalyzer(ICompilationUnit cu, CompilationUnit root, String[] importOrder, int threshold, int staticThreshold, boolean restoreExistingImports) { + this.compilationUnit= cu; + this.importOnDemandThreshold= threshold; + this.staticImportOnDemandThreshold= staticThreshold; + + this.filterImplicitImports= true; + this.findAmbiguousImports= true; //!restoreExistingImports; + + this.packageEntries= new ArrayList(20); + this.importsCreated= new ArrayList(); + this.staticImportsCreated= new ArrayList(); + this.flags= 0; + + this.replaceRange= evaluateReplaceRange(root); + if (restoreExistingImports) { + addExistingImports(root); + } + + PackageEntry[] order= new PackageEntry[importOrder.length]; + for (int i= 0; i < order.length; i++) { + String curr= importOrder[i]; + if (curr.length() > 0 && curr.charAt(0) == '#') { + curr= curr.substring(1); + order[i]= new PackageEntry(curr, curr, true); // static import group + } else { + order[i]= new PackageEntry(curr, curr, false); // normal import group + } + } + + addPreferenceOrderHolders(order); + } + + private int getSpacesBetweenImportGroups() { + try { + int num= Integer.parseInt(this.compilationUnit.getJavaProject().getOption(DefaultCodeFormatterConstants.FORMATTER_BLANK_LINES_BETWEEN_IMPORT_GROUPS, true)); + if (num >= 0) + return num; + } catch (NumberFormatException e) { + // fall through + } + return 1; + } + + private boolean insertSpaceBeforeSemicolon() { + return JavaCore.INSERT.equals(this.compilationUnit.getJavaProject().getOption(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_SEMICOLON, true)); + } + + private void addPreferenceOrderHolders(PackageEntry[] preferenceOrder) { + if (this.packageEntries.isEmpty()) { + // all new: copy the elements + for (int i= 0; i < preferenceOrder.length; i++) { + this.packageEntries.add(preferenceOrder[i]); + } + } else { + // match the preference order entries to existing imports + // entries not found are appended after the last successfully matched entry + + PackageEntry[] lastAssigned= new PackageEntry[preferenceOrder.length]; + + // find an existing package entry that matches most + for (int k= 0; k < this.packageEntries.size(); k++) { + PackageEntry entry= (PackageEntry) this.packageEntries.get(k); + if (!entry.isComment()) { + String currName= entry.getName(); + int currNameLen= currName.length(); + int bestGroupIndex= -1; + int bestGroupLen= -1; + for (int i= 0; i < preferenceOrder.length; i++) { + boolean currPrevStatic= preferenceOrder[i].isStatic(); + if (currPrevStatic == entry.isStatic()) { + String currPrefEntry= preferenceOrder[i].getName(); + int currPrefLen= currPrefEntry.length(); + if (currName.startsWith(currPrefEntry) && currPrefLen >= bestGroupLen) { + if (currPrefLen == currNameLen || currName.charAt(currPrefLen) == '.') { + if (bestGroupIndex == -1 || currPrefLen > bestGroupLen) { + bestGroupLen= currPrefLen; + bestGroupIndex= i; + } + } + } + } + } + if (bestGroupIndex != -1) { + entry.setGroupID(preferenceOrder[bestGroupIndex].getName()); + lastAssigned[bestGroupIndex]= entry; // remember last entry + } + } + } + // fill in not-assigned categories, keep partial order + int currAppendIndex= 0; + for (int i= 0; i < lastAssigned.length; i++) { + PackageEntry entry= lastAssigned[i]; + if (entry == null) { + PackageEntry newEntry= preferenceOrder[i]; + if (currAppendIndex == 0 && !newEntry.isStatic()) { + currAppendIndex= getIndexAfterStatics(); + } + this.packageEntries.add(currAppendIndex, newEntry); + currAppendIndex++; + } else { + currAppendIndex= this.packageEntries.indexOf(entry) + 1; + } + } + } + } + + private static String getQualifier(ImportDeclaration decl) { + String name= decl.getName().getFullyQualifiedName(); + return decl.isOnDemand() ? name : Signature.getQualifier(name); + } + + private static String getFullName(ImportDeclaration decl) { + String name= decl.getName().getFullyQualifiedName(); + return decl.isOnDemand() ? name + ".*": name; //$NON-NLS-1$ + } + + private void addExistingImports(CompilationUnit root) { + List/*ImportDeclaration*/ decls= root.imports(); + if (decls.isEmpty()) { + return; + } + PackageEntry currPackage= null; + + ImportDeclaration curr= (ImportDeclaration) decls.get(0); + int currOffset= curr.getStartPosition(); + int currLength= curr.getLength(); + int currEndLine= root.getLineNumber(currOffset + currLength); + + for (int i= 1; i < decls.size(); i++) { + boolean isStatic= curr.isStatic(); + String name= getFullName(curr); + String packName= getQualifier(curr); +//{ObjectTeams: added 'isBase()' (two occurrences): + boolean isBase= curr.isBase(); + if (currPackage == null || currPackage.compareTo(packName, isStatic, isBase) != 0) { + currPackage= new PackageEntry(packName, null, isStatic, isBase); +// SH} + this.packageEntries.add(currPackage); + } + + ImportDeclaration next= (ImportDeclaration) decls.get(i); + int nextOffset= next.getStartPosition(); + int nextLength= next.getLength(); + int nextOffsetLine= root.getLineNumber(nextOffset); + + // if next import is on a different line, modify the end position to the next line begin offset + if (currEndLine < nextOffsetLine) { + currEndLine++; + nextOffset= root.getPosition(currEndLine, 0); + } + currPackage.add(new ImportDeclEntry(name, isStatic, new Region(currOffset, nextOffset - currOffset))); +//{ObjectTeams: base import + if (isBase) + currPackage.getLast().setIsBase(true); +// SH} + currOffset= nextOffset; + curr= next; + + // add a comment entry for spacing between imports + if (currEndLine < nextOffsetLine) { + nextOffset= root.getPosition(nextOffsetLine, 0); + + currPackage= new PackageEntry(); // create a comment package entry for this + this.packageEntries.add(currPackage); + currPackage.add(new ImportDeclEntry(null, false, new Region(currOffset, nextOffset - currOffset))); + + currOffset= nextOffset; + } + currEndLine= root.getLineNumber(nextOffset + nextLength); + } + + boolean isStatic= curr.isStatic(); + String name= getFullName(curr); + String packName= getQualifier(curr); +//{ObjectTeams: added 'isBase' + boolean isBase= curr.isBase(); +/* orig: + if (currPackage == null || currPackage.compareTo(packName, isStatic) != 0) { + currPackage= new PackageEntry(packName, null, isStatic); + :giro */ + if (currPackage == null || currPackage.compareTo(packName, isStatic, isBase) != 0) { + currPackage= new PackageEntry(packName, null, isStatic, curr.isBase()); +// SH} + this.packageEntries.add(currPackage); + } + int length= this.replaceRange.getOffset() + this.replaceRange.getLength() - curr.getStartPosition(); + currPackage.add(new ImportDeclEntry(name, isStatic, new Region(curr.getStartPosition(), length))); +//{ObjectTeams: base import + if (isBase) + currPackage.getLast().setIsBase(true); +//SH} + } + + /** + * Sets that implicit imports (types in default package, CU- package and + * 'java.lang') should not be created. Note that this is a heuristic filter and can + * lead to missing imports, e.g. in cases where a type is forced to be specified + * due to a name conflict. + * By default, the filter is enabled. + * @param filterImplicitImports The filterImplicitImports to set + */ + public void setFilterImplicitImports(boolean filterImplicitImports) { + this.filterImplicitImports= filterImplicitImports; + } + + /** + * When set searches for imports that can not be folded into on-demand + * imports but must be specified explicitly + * @param findAmbiguousImports The new value + */ + public void setFindAmbiguousImports(boolean findAmbiguousImports) { + this.findAmbiguousImports= findAmbiguousImports; + } + + private static class PackageMatcher { + private String newName; + private String bestName; + private int bestMatchLen; + + public PackageMatcher() { + // initialization in 'initialize' + } + + public void initialize(String newImportName, String bestImportName) { + this.newName= newImportName; + this.bestName= bestImportName; + this.bestMatchLen= getCommonPrefixLength(bestImportName, newImportName); + } + + public boolean isBetterMatch(String currName, boolean preferCurr) { + boolean isBetter; + int currMatchLen= getCommonPrefixLength(currName, this.newName); + int matchDiff= currMatchLen - this.bestMatchLen; + if (matchDiff == 0) { + if (currMatchLen == this.newName.length() && currMatchLen == currName.length() && currMatchLen == this.bestName.length()) { + // duplicate entry and complete match + isBetter= preferCurr; + } else { + isBetter= sameMatchLenTest(currName); + } + } else { + isBetter= (matchDiff > 0); // curr has longer match + } + if (isBetter) { + this.bestName= currName; + this.bestMatchLen= currMatchLen; + } + return isBetter; + } + + private boolean sameMatchLenTest(String currName) { + int matchLen= this.bestMatchLen; + // known: bestName and currName differ from newName at position 'matchLen' + // currName and bestName don't have to differ at position 'matchLen' + + // determine the order and return true if currName is closer to newName + char newChar= getCharAt(this.newName, matchLen); + char currChar= getCharAt(currName, matchLen); + char bestChar= getCharAt(this.bestName, matchLen); + + if (newChar < currChar) { + if (bestChar < newChar) { // b < n < c + return (currChar - newChar) < (newChar - bestChar); // -> (c - n) < (n - b) + } else { // n < b && n < c + if (currChar == bestChar) { // longer match between curr and best + return false; // keep curr and best together, new should be before both + } else { + return currChar < bestChar; // -> (c < b) + } + } + } else { + if (bestChar > newChar) { // c < n < b + return (newChar - currChar) < (bestChar - newChar); // -> (n - c) < (b - n) + } else { // n > b && n > c + if (currChar == bestChar) { // longer match between curr and best + return true; // keep curr and best together, new should be ahead of both + } else { + return currChar > bestChar; // -> (c > b) + } + } + } + } + } + + /* package */ static int getCommonPrefixLength(String s, String t) { + int len= Math.min(s.length(), t.length()); + for (int i= 0; i < len; i++) { + if (s.charAt(i) != t.charAt(i)) { + return i; + } + } + return len; + } + + /* package */ static char getCharAt(String str, int index) { + if (str.length() > index) { + return str.charAt(index); + } + return 0; + } + +//{ObjectTeams: added: 'isBase': + private PackageEntry findBestMatch(String newName, boolean isStatic, boolean isBase) { +// SH} + if (this.packageEntries.isEmpty()) { + return null; + } + String groupId= null; + int longestPrefix= -1; + // find the matching group + for (int i= 0; i < this.packageEntries.size(); i++) { + PackageEntry curr= (PackageEntry) this.packageEntries.get(i); +//{ObjectTeams: new check: +/* orig: + if (isStatic == curr.isStatic()) { + :giro */ + if (isStatic == curr.isStatic() && isBase == curr.isBase()) { +// SH} + String currGroup= curr.getGroupID(); + if (currGroup != null && newName.startsWith(currGroup)) { + int prefixLen= currGroup.length(); + if (prefixLen == newName.length()) { + return curr; // perfect fit, use entry + } + if ((newName.charAt(prefixLen) == '.' || prefixLen == 0) && prefixLen > longestPrefix) { + longestPrefix= prefixLen; + groupId= currGroup; + } + } + } + } + PackageEntry bestMatch= null; + PackageMatcher matcher= new PackageMatcher(); + matcher.initialize(newName, ""); //$NON-NLS-1$ + for (int i= 0; i < this.packageEntries.size(); i++) { // find the best match with the same group + PackageEntry curr= (PackageEntry) this.packageEntries.get(i); + if (!curr.isComment() && curr.isStatic() == isStatic +//{ObjectTeams: new check: + && isBase == curr.isBase()) + { +// SH} + if (groupId == null || groupId.equals(curr.getGroupID())) { + boolean preferrCurr= (bestMatch == null) || (curr.getNumberOfImports() > bestMatch.getNumberOfImports()); + if (matcher.isBetterMatch(curr.getName(), preferrCurr)) { + bestMatch= curr; + } + } + } + } + return bestMatch; + } + + private static boolean isImplicitImport(String qualifier, ICompilationUnit cu) { + if (JAVA_LANG.equals(qualifier)) { + return true; + } + String packageName= cu.getParent().getElementName(); + if (qualifier.equals(packageName)) { + return true; + } + String mainTypeName= JavaCore.removeJavaLikeExtension(cu.getElementName()); + if (packageName.length() == 0) { + return qualifier.equals(mainTypeName); + } + return qualifier.equals(packageName +'.' + mainTypeName); + } + +//{ObjectTeams: added param 'isBase': + public void addImport(String fullTypeName, boolean isStatic, boolean isBase) { + String typeContainerName= Signature.getQualifier(fullTypeName); + ImportDeclEntry decl= new ImportDeclEntry(fullTypeName, isStatic, null); + sortIn(typeContainerName, decl, isStatic, isBase); + } +// SH} +//{ObjectTeams: added isBase: +/* orig: + public boolean removeImport(String qualifiedName, boolean isStatic) { + :giro */ + public boolean removeImport(String qualifiedName, boolean isStatic, boolean isBase) { +// orig: + String containerName= Signature.getQualifier(qualifiedName); + + int nPackages= this.packageEntries.size(); + for (int i= 0; i < nPackages; i++) { + PackageEntry entry= (PackageEntry) this.packageEntries.get(i); +/* + if (entry.compareTo(containerName, isStatic) == 0) { + :giro */ + if (entry.compareTo(containerName, isStatic, isBase) == 0) { +// SH} + if (entry.remove(qualifiedName, isStatic)) { + return true; + } + } + } + return false; + } + +//{ObjectTeams: base import: + public void addBaseImport(String fullTypeName) { + String typeContainerName= Signature.getQualifier(fullTypeName); + ImportDeclEntry decl= new ImportDeclEntry(fullTypeName, false, null); + decl.setIsBase(true); + sortIn(typeContainerName, decl, false, true); + } + // set flag. + public boolean setBase(String fullTypeName) { + String containerName= Signature.getQualifier(fullTypeName); + int nPackages= this.packageEntries.size(); + for (int i= 0; i < nPackages; i++) { + PackageEntry entry= (PackageEntry) this.packageEntries.get(i); + if (entry.compareTo(containerName, /*isStatic*/false, /*isBase*/false) == 0) { + ImportDeclEntry importEntry = entry.find(Signature.getSimpleName(fullTypeName)); + importEntry.setIsBase(true); + return true; + } + } + return false; + } +// SH} + + private int getIndexAfterStatics() { + for (int i= 0; i < this.packageEntries.size(); i++) { + if (!((PackageEntry) this.packageEntries.get(i)).isStatic()) { + return i; + } + } + return this.packageEntries.size(); + } + +//{ObjectTeams: +/* orig: + private void sortIn(String typeContainerName, ImportDeclEntry decl, boolean isStatic) { + PackageEntry bestMatch= findBestMatch(typeContainerName, isStatic); + :giro */ + private void sortIn(String typeContainerName, ImportDeclEntry decl, boolean isStatic, boolean isBase) { + PackageEntry bestMatch= findBestMatch(typeContainerName, isStatic, isBase); +// SH} + if (bestMatch == null) { +//{ObjectTeams: isBase: +/* orig: + PackageEntry packEntry= new PackageEntry(typeContainerName, null, isStatic); + :giro */ + PackageEntry packEntry= new PackageEntry(typeContainerName, null, isStatic, isBase); +// SH} + packEntry.add(decl); + int insertPos= packEntry.isStatic() ? 0 : getIndexAfterStatics(); +//{ObjectTeams: + if (isBase) insertPos = getIndexAfterRegular(); +// SH} + this.packageEntries.add(insertPos, packEntry); + } else { + int cmp= typeContainerName.compareTo(bestMatch.getName()); + if (cmp == 0) { + bestMatch.sortIn(decl); + } else { + // create a new package entry + String group= bestMatch.getGroupID(); + if (group != null) { + if (!typeContainerName.startsWith(group)) { + group= null; + } + } +//{ObjectTeams: isBase: +/* orig: + PackageEntry packEntry= new PackageEntry(typeContainerName, group, isStatic); + :giro */ + PackageEntry packEntry= new PackageEntry(typeContainerName, group, isStatic, isBase); +// SH} + packEntry.add(decl); + int index= this.packageEntries.indexOf(bestMatch); + if (cmp < 0) { // insert ahead of best match + this.packageEntries.add(index, packEntry); + } else { // insert after best match + this.packageEntries.add(index + 1, packEntry); + } + } + } + } +//{ObjectTeams: similar to getIndexAfterStatics: + private int getIndexAfterRegular() { + for (int i= 0; i < this.packageEntries.size(); i++) { + if (((PackageEntry) this.packageEntries.get(i)).isBase()) { + return i; + } + } + return this.packageEntries.size(); + } +// SH} + + private IRegion evaluateReplaceRange(CompilationUnit root) { + List imports= root.imports(); + if (!imports.isEmpty()) { + ImportDeclaration first= (ImportDeclaration) imports.get(0); + ImportDeclaration last= (ImportDeclaration) imports.get(imports.size() - 1); + + int startPos= first.getStartPosition(); // no extended range for first: bug 121428 + int endPos= root.getExtendedStartPosition(last) + root.getExtendedLength(last); + int endLine= root.getLineNumber(endPos); + if (endLine > 0) { + int nextLinePos= root.getPosition(endLine + 1, 0); + if (nextLinePos >= 0) { + int firstTypePos= getFirstTypeBeginPos(root); + if (firstTypePos != -1 && firstTypePos < nextLinePos) { + endPos= firstTypePos; + } else { + endPos= nextLinePos; + } + } + } + return new Region(startPos, endPos - startPos); + } else { + int start= getPackageStatementEndPos(root); + return new Region(start, 0); + } + } + + public MultiTextEdit getResultingEdits(IProgressMonitor monitor) throws JavaModelException { + if (monitor == null) { + monitor= new NullProgressMonitor(); + } + try { + int importsStart= this.replaceRange.getOffset(); + int importsLen= this.replaceRange.getLength(); + + String lineDelim= this.compilationUnit.findRecommendedLineSeparator(); + IBuffer buffer= this.compilationUnit.getBuffer(); + + int currPos= importsStart; + MultiTextEdit resEdit= new MultiTextEdit(); + + if ((this.flags & F_NEEDS_LEADING_DELIM) != 0) { + // new import container + resEdit.addChild(new InsertEdit(currPos, lineDelim)); + } + + PackageEntry lastPackage= null; + + Set onDemandConflicts= null; + if (this.findAmbiguousImports) { + onDemandConflicts= evaluateStarImportConflicts(monitor); + } + + int spacesBetweenGroups= getSpacesBetweenImportGroups(); + + ArrayList stringsToInsert= new ArrayList(); + + int nPackageEntries= this.packageEntries.size(); + for (int i= 0; i < nPackageEntries; i++) { + PackageEntry pack= (PackageEntry) this.packageEntries.get(i); + int nImports= pack.getNumberOfImports(); + + if (this.filterImplicitImports && !pack.isStatic() && isImplicitImport(pack.getName(), this.compilationUnit)) { + pack.removeAllNew(onDemandConflicts); + nImports= pack.getNumberOfImports(); + } + if (nImports == 0) { + continue; + } + + + if (spacesBetweenGroups > 0) { + // add a space between two different groups by looking at the two adjacent imports + if (lastPackage != null && !pack.isComment() && !pack.isSameGroup(lastPackage)) { + ImportDeclEntry last= lastPackage.getImportAt(lastPackage.getNumberOfImports() - 1); + ImportDeclEntry first= pack.getImportAt(0); + if (!lastPackage.isComment() && (last.isNew() || first.isNew())) { + for (int k= spacesBetweenGroups; k > 0; k--) { + stringsToInsert.add(lineDelim); + } + } + } + } + lastPackage= pack; + + boolean isStatic= pack.isStatic(); + int threshold= isStatic ? this.staticImportOnDemandThreshold : this.importOnDemandThreshold; + + boolean doStarImport= pack.hasStarImport(threshold, onDemandConflicts); + if (doStarImport && (pack.find("*") == null)) { //$NON-NLS-1$ + String starImportString= pack.getName() + ".*"; //$NON-NLS-1$ +//{ObjectTeams: new 3. param: + String str= getNewImportString(starImportString, isStatic, false, lineDelim); +// SH} + stringsToInsert.add(str); + } + + for (int k= 0; k < nImports; k++) { + ImportDeclEntry currDecl= pack.getImportAt(k); + IRegion region= currDecl.getSourceRange(); + + if (region == null) { // new entry + if (!doStarImport || currDecl.isOnDemand() || (onDemandConflicts != null && onDemandConflicts.contains(currDecl.getSimpleName()))) { +//{ObjectTeams: new 3. param: + String str= getNewImportString(currDecl.getElementName(), isStatic, currDecl.isBase(), lineDelim); +// SH} + stringsToInsert.add(str); + } + } else { + if (!doStarImport || currDecl.isOnDemand() || onDemandConflicts == null || onDemandConflicts.contains(currDecl.getSimpleName())) { + int offset= region.getOffset(); + removeAndInsertNew(buffer, currPos, offset, stringsToInsert, resEdit); + stringsToInsert.clear(); +//{ObjectTeams: + if (currDecl.isBase()) { + int endPos = offset+region.getLength(); + int importPos = findInBuffer(buffer, "import", offset, endPos); //$NON-NLS-1$ + int basePos = findInBuffer(buffer, "base", importPos, endPos); //$NON-NLS-1$ + if (basePos == -1) // "base" not yet set + resEdit.addChild(new InsertEdit(importPos+"import ".length(), "base ")); //$NON-NLS-1$ //$NON-NLS-2$ + } +// SH} + currPos= offset + region.getLength(); + } + } + } + } + + int end= importsStart + importsLen; + removeAndInsertNew(buffer, currPos, end, stringsToInsert, resEdit); + + if (importsLen == 0) { + if (!this.importsCreated.isEmpty() || !this.staticImportsCreated.isEmpty()) { // new import container + if ((this.flags & F_NEEDS_TRAILING_DELIM) != 0) { + resEdit.addChild(new InsertEdit(currPos, lineDelim)); + } + } else { + return new MultiTextEdit(); // no changes + } + } + return resEdit; + } finally { + monitor.done(); + } + } + + private void removeAndInsertNew(IBuffer buffer, int contentOffset, int contentEnd, ArrayList stringsToInsert, MultiTextEdit resEdit) { + int pos= contentOffset; + for (int i= 0; i < stringsToInsert.size(); i++) { + String curr= (String) stringsToInsert.get(i); + int idx= findInBuffer(buffer, curr, pos, contentEnd); + if (idx != -1) { + if (idx != pos) { + resEdit.addChild(new DeleteEdit(pos, idx - pos)); + } + pos= idx + curr.length(); + } else { + resEdit.addChild(new InsertEdit(pos, curr)); + } + } + if (pos < contentEnd) { + resEdit.addChild(new DeleteEdit(pos, contentEnd - pos)); + } + } + + private int findInBuffer(IBuffer buffer, String str, int start, int end) { + int pos= start; + int len= str.length(); + if (pos + len > end || str.length() == 0) { + return -1; + } + char first= str.charAt(0); + int step= str.indexOf(first, 1); + if (step == -1) { + step= len; + } + while (pos + len <= end) { + if (buffer.getChar(pos) == first) { + int k= 1; + while (k < len && buffer.getChar(pos + k) == str.charAt(k)) { + k++; + } + if (k == len) { + return pos; // found + } + if (k < step) { + pos+= k; + } else { + pos+= step; + } + } else { + pos++; + } + } + return -1; + } + + private Set evaluateStarImportConflicts(IProgressMonitor monitor) throws JavaModelException { + //long start= System.currentTimeMillis(); + + final HashSet/*String*/ onDemandConflicts= new HashSet(); + + IJavaSearchScope scope= SearchEngine.createJavaSearchScope(new IJavaElement[] { this.compilationUnit.getJavaProject() }); + + ArrayList/*<char[][]>*/ starImportPackages= new ArrayList(); + ArrayList/*<char[][]>*/ simpleTypeNames= new ArrayList(); + int nPackageEntries= this.packageEntries.size(); + for (int i= 0; i < nPackageEntries; i++) { + PackageEntry pack= (PackageEntry) this.packageEntries.get(i); + if (!pack.isStatic() && pack.hasStarImport(this.importOnDemandThreshold, null)) { + starImportPackages.add(pack.getName().toCharArray()); + for (int k= 0; k < pack.getNumberOfImports(); k++) { + ImportDeclEntry curr= pack.getImportAt(k); + if (!curr.isOnDemand() && !curr.isComment()) { + simpleTypeNames.add(curr.getSimpleName().toCharArray()); + } + } + } + } + if (starImportPackages.isEmpty()) { + return null; + } + + starImportPackages.add(this.compilationUnit.getParent().getElementName().toCharArray()); + starImportPackages.add(JAVA_LANG.toCharArray()); + + char[][] allPackages= (char[][]) starImportPackages.toArray(new char[starImportPackages.size()][]); + char[][] allTypes= (char[][]) simpleTypeNames.toArray(new char[simpleTypeNames.size()][]); + + TypeNameRequestor requestor= new TypeNameRequestor() { + HashMap foundTypes= new HashMap(); + + private String getTypeContainerName(char[] packageName, char[][] enclosingTypeNames) { + StringBuffer buf= new StringBuffer(); + buf.append(packageName); + for (int i= 0; i < enclosingTypeNames.length; i++) { + if (buf.length() > 0) + buf.append('.'); + buf.append(enclosingTypeNames[i]); + } + return buf.toString(); + } + + public void acceptType(int modifiers, char[] packageName, char[] simpleTypeName, char[][] enclosingTypeNames, String path) { + String name= new String(simpleTypeName); + String containerName= getTypeContainerName(packageName, enclosingTypeNames); + + String oldContainer= (String) this.foundTypes.put(name, containerName); + if (oldContainer != null && !oldContainer.equals(containerName)) { + onDemandConflicts.add(name); + } + } + }; + new SearchEngine().searchAllTypeNames(allPackages, allTypes, scope, requestor, IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH, monitor); + return onDemandConflicts; + } + +//{ObjectTeams: added 3. parameter + private String getNewImportString(String importName, boolean isStatic, boolean isBase, String lineDelim) { +// SH} + StringBuffer buf= new StringBuffer(); + buf.append("import "); //$NON-NLS-1$ + if (isStatic) { + buf.append("static "); //$NON-NLS-1$ + } +//{ObjectTeams: base import: + else if (isBase) + buf.append("base "); //$NON-NLS-1$ +// SH} + + buf.append(importName); + if (insertSpaceBeforeSemicolon()) buf.append(' '); + buf.append(';'); + buf.append(lineDelim); + + if (isStatic) { + this.staticImportsCreated.add(importName); + } else { + this.importsCreated.add(importName); + } + return buf.toString(); + } + + private static int getFirstTypeBeginPos(CompilationUnit root) { + List types= root.types(); + if (!types.isEmpty()) { + return root.getExtendedStartPosition(((ASTNode) types.get(0))); + } + return -1; + } + + private int getPackageStatementEndPos(CompilationUnit root) { + PackageDeclaration packDecl= root.getPackage(); + if (packDecl != null) { + int afterPackageStatementPos= -1; + int lineNumber= root.getLineNumber(packDecl.getStartPosition() + packDecl.getLength()); + if (lineNumber >= 0) { + int lineAfterPackage= lineNumber + 1; + afterPackageStatementPos= root.getPosition(lineAfterPackage, 0); + } + if (afterPackageStatementPos < 0) { + this.flags|= F_NEEDS_LEADING_DELIM; + return packDecl.getStartPosition() + packDecl.getLength(); + } + int firstTypePos= getFirstTypeBeginPos(root); + if (firstTypePos != -1 && firstTypePos <= afterPackageStatementPos) { + this.flags|= F_NEEDS_TRAILING_DELIM; + if (firstTypePos == afterPackageStatementPos) { + this.flags|= F_NEEDS_LEADING_DELIM; + } + return firstTypePos; + } + this.flags|= F_NEEDS_LEADING_DELIM; + return afterPackageStatementPos; // insert a line after after package statement + } + this.flags |= F_NEEDS_TRAILING_DELIM; + return 0; + } + + public String toString() { + int nPackages= this.packageEntries.size(); + StringBuffer buf= new StringBuffer("\n-----------------------\n"); //$NON-NLS-1$ + for (int i= 0; i < nPackages; i++) { + PackageEntry entry= (PackageEntry) this.packageEntries.get(i); + if (entry.isStatic()) { + buf.append("static "); //$NON-NLS-1$ + } + buf.append(entry.toString()); + } + return buf.toString(); + } + + private static final class ImportDeclEntry { + + private String elementName; + private IRegion sourceRange; + private final boolean isStatic; +//{ObjectTeams: base import + private boolean isBase = false; +// SH} + + public ImportDeclEntry(String elementName, boolean isStatic, IRegion sourceRange) { + this.elementName= elementName; + this.sourceRange= sourceRange; + this.isStatic= isStatic; + } + + public String getElementName() { + return this.elementName; + } + + public int compareTo(String fullName, boolean isStaticImport) { + int cmp= this.elementName.compareTo(fullName); + if (cmp == 0) { + if (this.isStatic == isStaticImport) { + return 0; + } + return this.isStatic ? -1 : 1; + } + return cmp; + } + + public String getSimpleName() { + return Signature.getSimpleName(this.elementName); + } + + public boolean isOnDemand() { + return this.elementName != null && this.elementName.endsWith(".*"); //$NON-NLS-1$ + } + + public boolean isStatic() { + return this.isStatic; + } + + public boolean isNew() { + return this.sourceRange == null; + } + + public boolean isComment() { + return this.elementName == null; + } + + public IRegion getSourceRange() { + return this.sourceRange; + } +//{ObjectTeams: base import: + public void setIsBase(boolean flag) { + this.isBase = flag; + } + public boolean isBase() { + return this.isBase; + } +// SH} + } + + /* + * Internal element for the import structure: A container for imports + * of all types from the same package + */ + private final static class PackageEntry { + private String name; + private ArrayList importEntries; + private String group; + private boolean isStatic; +//{ObjectTeams: base import + private boolean isBase; +// SH} + + /** + * Comment package entry + */ + public PackageEntry() { + this("!", null, false); //$NON-NLS-1$ + } + + /** + * @param name Name of the package entry. e.g. org.eclipse.jdt.ui, containing imports like + * org.eclipse.jdt.ui.JavaUI. + * @param group The index of the preference order entry assigned + * different group id's will result in spacers between the entries + */ + public PackageEntry(String name, String group, boolean isStatic) { + this.name= name; + this.importEntries= new ArrayList(5); + this.group= group; + this.isStatic= isStatic; + } +//{ObjectTeams: base import + public PackageEntry(String name, String group, boolean isStatic, boolean isBase) { + this(name, group, isStatic); + this.isBase = isBase; + } + public boolean isBase() { + return this.isBase; + } +// SH} + + + public boolean isStatic() { + return this.isStatic; + } + +//{ObjectTeams: also compare base flag: +/* orig: + public int compareTo(String otherName, boolean isOtherStatic) { + :giro */ + public int compareTo(String otherName, boolean isOtherStatic, boolean isOtherBase) + { +// SH} + int cmp= this.name.compareTo(otherName); + if (cmp == 0) { + if (this.isStatic == isOtherStatic) { +//{ObjectTeams: more comparison: + if (this.isBase == isOtherBase) +// SH} + return 0; + } + return this.isStatic ? -1 : 1; + } + return cmp; + } + + public void sortIn(ImportDeclEntry imp) { + String fullImportName= imp.getElementName(); + int insertPosition= -1; + int nInports= this.importEntries.size(); + for (int i= 0; i < nInports; i++) { + ImportDeclEntry curr= getImportAt(i); + if (!curr.isComment()) { + int cmp= curr.compareTo(fullImportName, imp.isStatic()); + if (cmp == 0) { + return; // exists already + } else if (cmp > 0 && insertPosition == -1) { + insertPosition= i; + } + } + } + if (insertPosition == -1) { + this.importEntries.add(imp); + } else { + this.importEntries.add(insertPosition, imp); + } + } + + + public void add(ImportDeclEntry imp) { + this.importEntries.add(imp); + } + + public ImportDeclEntry find(String simpleName) { + int nInports= this.importEntries.size(); + for (int i= 0; i < nInports; i++) { + ImportDeclEntry curr= getImportAt(i); + if (!curr.isComment()) { + String currName= curr.getElementName(); + if (currName.endsWith(simpleName)) { + int dotPos= currName.length() - simpleName.length() - 1; + if ((dotPos == -1) || (dotPos > 0 && currName.charAt(dotPos) == '.')) { + return curr; + } + } + } + } + return null; + } + + public boolean remove(String fullName, boolean isStaticImport) { + int nInports= this.importEntries.size(); + for (int i= 0; i < nInports; i++) { + ImportDeclEntry curr= getImportAt(i); + if (!curr.isComment() && curr.compareTo(fullName, isStaticImport) == 0) { + this.importEntries.remove(i); + return true; + } + } + return false; + } + + public void removeAllNew(Set onDemandConflicts) { + int nInports= this.importEntries.size(); + for (int i= nInports - 1; i >= 0; i--) { + ImportDeclEntry curr= getImportAt(i); + if (curr.isNew() /*&& (onDemandConflicts == null || onDemandConflicts.contains(curr.getSimpleName()))*/) { + this.importEntries.remove(i); + } + } + } + + public ImportDeclEntry getImportAt(int index) { + return (ImportDeclEntry) this.importEntries.get(index); + } + + public boolean hasStarImport(int threshold, Set explicitImports) { + if (isComment() || isDefaultPackage()) { // can not star import default package + return false; + } + int nImports= getNumberOfImports(); + int count= 0; + boolean containsNew= false; + for (int i= 0; i < nImports; i++) { + ImportDeclEntry curr= getImportAt(i); + if (curr.isOnDemand()) { + return true; + } + if (!curr.isComment()) { + count++; + boolean isExplicit= !curr.isStatic() && (explicitImports != null) && explicitImports.contains(curr.getSimpleName()); + containsNew |= curr.isNew() && !isExplicit; + } + } + return (count >= threshold) && containsNew; + } + + public int getNumberOfImports() { + return this.importEntries.size(); + } + + public String getName() { + return this.name; + } + + public String getGroupID() { + return this.group; + } + + public void setGroupID(String groupID) { + this.group= groupID; + } + + public boolean isSameGroup(PackageEntry other) { + if (this.group == null) { + return other.getGroupID() == null; + } else { + return this.group.equals(other.getGroupID()) && (this.isStatic == other.isStatic()); + } + } + +//{ObjectTeams: restore method removed as of 3.5: + public ImportDeclEntry getLast() { + int nImports= getNumberOfImports(); + if (nImports > 0) { + return getImportAt(nImports - 1); + } + return null; + } +// SH} + + public boolean isComment() { + return "!".equals(this.name); //$NON-NLS-1$ + } + + public boolean isDefaultPackage() { + return this.name.length() == 0; + } + + public String toString() { + StringBuffer buf= new StringBuffer(); + if (isComment()) { + buf.append("comment\n"); //$NON-NLS-1$ + } else { + buf.append(this.name); buf.append(", groupId: "); buf.append(this.group); buf.append("\n"); //$NON-NLS-1$ //$NON-NLS-2$ + int nImports= getNumberOfImports(); + for (int i= 0; i < nImports; i++) { + ImportDeclEntry curr= getImportAt(i); + buf.append(" "); //$NON-NLS-1$ + if (curr.isStatic()) { + buf.append("static "); //$NON-NLS-1$ + } +//{ObjectTeams: + else if (curr.isBase()) { + buf.append("base "); //$NON-NLS-1$ + } +// SH} + buf.append(curr.getSimpleName()); + if (curr.isNew()) { + buf.append(" (new)"); //$NON-NLS-1$ + } + buf.append("\n"); //$NON-NLS-1$ + } + } + return buf.toString(); + } + } + + public String[] getCreatedImports() { + return (String[]) this.importsCreated.toArray(new String[this.importsCreated.size()]); + } + + public String[] getCreatedStaticImports() { + return (String[]) this.staticImportsCreated.toArray(new String[this.staticImportsCreated.size()]); + } + +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/LineCommentEndOffsets.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/LineCommentEndOffsets.java new file mode 100644 index 000000000..772fa6aad --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/LineCommentEndOffsets.java @@ -0,0 +1,85 @@ +/******************************************************************************* + * Copyright (c) 2000, 2009 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.internal.core.dom.rewrite; + +import java.util.Arrays; +import java.util.List; + +import org.eclipse.jdt.core.dom.LineComment; +import org.eclipse.jdt.core.formatter.IndentManipulation; +import org.eclipse.jdt.internal.compiler.util.Util; + +public class LineCommentEndOffsets { + + private int[] offsets; + private final List commentList; + + public LineCommentEndOffsets(List commentList) { + this.commentList= commentList; + this.offsets= null; // create on demand + } + + private int[] getOffsets() { + if (this.offsets == null) { + if (this.commentList != null) { + int nComments= this.commentList.size(); + // count the number of line comments + int count= 0; + for (int i= 0; i < nComments; i++) { + Object curr= this.commentList.get(i); + if (curr instanceof LineComment) { + count++; + } + } + // fill the offset table + this.offsets= new int[count]; + for (int i= 0, k= 0; i < nComments; i++) { + Object curr= this.commentList.get(i); + if (curr instanceof LineComment) { + LineComment comment= (LineComment) curr; + this.offsets[k++]= comment.getStartPosition() + comment.getLength(); + } + } + } else { + this.offsets= Util.EMPTY_INT_ARRAY; + } + } + return this.offsets; + } + + public boolean isEndOfLineComment(int offset) { + return offset >= 0 && Arrays.binarySearch(getOffsets(), offset) >= 0; + } + + public boolean isEndOfLineComment(int offset, char[] content) { + if (offset < 0 || (offset < content.length && !IndentManipulation.isLineDelimiterChar(content[offset]))) { + return false; + } + return Arrays.binarySearch(getOffsets(), offset) >= 0; + } + + public boolean remove(int offset) { + int[] offsetArray= getOffsets(); // returns the shared array + int index= Arrays.binarySearch(offsetArray, offset); + if (index >= 0) { + if (index > 0) { + // shift from the beginning and insert -1 (smallest number) at the beginning + // 1, 2, 3, x, 4, 5 -> -1, 1, 2, 3, 4, 5 + System.arraycopy(offsetArray, 0, offsetArray, 1, index); + } + offsetArray[0]= -1; + return true; + } + return false; + } + +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/LineInformation.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/LineInformation.java new file mode 100644 index 000000000..fca9ea5e0 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/LineInformation.java @@ -0,0 +1,59 @@ +/******************************************************************************* + * Copyright (c) 2000, 2009 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.jdt.internal.core.dom.rewrite; + +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IDocument; + +/** + * + */ +public abstract class LineInformation { + + public static LineInformation create(final IDocument doc) { + return new LineInformation() { + public int getLineOfOffset(int offset) { + try { + return doc.getLineOfOffset(offset); + } catch (BadLocationException e) { + return -1; + } + } + + public int getLineOffset(int line) { + try { + return doc.getLineOffset(line); + } catch (BadLocationException e) { + return -1; + } + } + }; + } + + public static LineInformation create(final CompilationUnit astRoot) { + return new LineInformation() { + public int getLineOfOffset(int offset) { + return astRoot.getLineNumber(offset) - 1; + } + public int getLineOffset(int line) { + return astRoot.getPosition(line + 1, 0); + } + }; + } + + + + public abstract int getLineOfOffset(int offset); + public abstract int getLineOffset(int line); + +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ListRewriteEvent.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ListRewriteEvent.java new file mode 100644 index 000000000..e32af7fee --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ListRewriteEvent.java @@ -0,0 +1,215 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.core.dom.rewrite; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jdt.core.dom.ASTNode; + +/** + * + */ +public class ListRewriteEvent extends RewriteEvent { + + public final static int NEW= 1; + public final static int OLD= 2; + public final static int BOTH= NEW | OLD; + + /** original list of 'ASTNode' */ + private List originalNodes; + + /** list of type 'RewriteEvent' */ + private List listEntries; + + /** + * Creates a ListRewriteEvent from the original ASTNodes. The resulting event + * represents the unmodified list. + * @param originalNodes The original nodes (type ASTNode) + */ + public ListRewriteEvent(List originalNodes) { + this.originalNodes= new ArrayList(originalNodes); + } + + /** + * Creates a ListRewriteEvent from existing rewrite events. + * @param children The rewrite events for this list. + */ + public ListRewriteEvent(RewriteEvent[] children) { + this.listEntries= new ArrayList(children.length * 2); + this.originalNodes= new ArrayList(children.length * 2); + for (int i= 0; i < children.length; i++) { + RewriteEvent curr= children[i]; + this.listEntries.add(curr); + if (curr.getOriginalValue() != null) { + this.originalNodes.add(curr.getOriginalValue()); + } + } + } + + private List getEntries() { + if (this.listEntries == null) { + // create if not yet existing + int nNodes= this.originalNodes.size(); + this.listEntries= new ArrayList(nNodes * 2); + for (int i= 0; i < nNodes; i++) { + ASTNode node= (ASTNode) this.originalNodes.get(i); + // all nodes unchanged + this.listEntries.add(new NodeRewriteEvent(node, node)); + } + } + return this.listEntries; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.corext.dom.ASTRewriteChange#getChangeKind() + */ + public int getChangeKind() { + if (this.listEntries != null) { + for (int i= 0; i < this.listEntries.size(); i++) { + RewriteEvent curr= (RewriteEvent) this.listEntries.get(i); + if (curr.getChangeKind() != UNCHANGED) { + return CHILDREN_CHANGED; + } + } + } + return UNCHANGED; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.corext.dom.ASTRewriteChange#isListChange() + */ + public boolean isListRewrite() { + return true; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.corext.dom.RewriteEvent#getChildren() + */ + public RewriteEvent[] getChildren() { + List entries= getEntries(); + return (RewriteEvent[]) entries.toArray(new RewriteEvent[entries.size()]); + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.corext.dom.RewriteEvent#getOriginalNode() + */ + public Object getOriginalValue() { + return this.originalNodes; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.corext.dom.RewriteEvent#getNewValue() + */ + public Object getNewValue() { + List entries= getEntries(); + ArrayList res= new ArrayList(entries.size()); + for (int i= 0; i < entries.size(); i++) { + RewriteEvent curr= (RewriteEvent) entries.get(i); + Object newVal= curr.getNewValue(); + if (newVal != null) { + res.add(newVal); + } + } + return res; + } + + // API to modify the list nodes + + public RewriteEvent removeEntry(ASTNode originalEntry) { + return replaceEntry(originalEntry, null); + } + + public RewriteEvent replaceEntry(ASTNode entry, ASTNode newEntry) { + if (entry == null) { + throw new IllegalArgumentException(); + } + + List entries= getEntries(); + int nEntries= entries.size(); + for (int i= 0; i < nEntries; i++) { + NodeRewriteEvent curr= (NodeRewriteEvent) entries.get(i); + if (curr.getOriginalValue() == entry || curr.getNewValue() == entry) { + curr.setNewValue(newEntry); + if (curr.getNewValue() == null && curr.getOriginalValue() == null) { // removed an inserted node + entries.remove(i); + return null; + } + return curr; + } + } + return null; + } + + public void revertChange(NodeRewriteEvent event) { + Object originalValue = event.getOriginalValue(); + if (originalValue == null) { + List entries= getEntries(); + entries.remove(event); + } else { + event.setNewValue(originalValue); + } + } + + public int getIndex(ASTNode node, int kind) { + List entries= getEntries(); + for (int i= entries.size() - 1; i >= 0; i--) { + RewriteEvent curr= (RewriteEvent) entries.get(i); + if (((kind & OLD) != 0) && (curr.getOriginalValue() == node)) { + return i; + } + if (((kind & NEW) != 0) && (curr.getNewValue() == node)) { + return i; + } + } + return -1; + } + + public RewriteEvent insert(ASTNode insertedNode, int insertIndex) { + NodeRewriteEvent change= new NodeRewriteEvent(null, insertedNode); + if (insertIndex != -1) { + getEntries().add(insertIndex, change); + } else { + getEntries().add(change); + } + return change; + } + + public void setNewValue(ASTNode newValue, int insertIndex) { + NodeRewriteEvent curr= (NodeRewriteEvent) getEntries().get(insertIndex); + curr.setNewValue(newValue); + } + + public int getChangeKind(int index) { + return ((NodeRewriteEvent) getEntries().get(index)).getChangeKind(); + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + public String toString() { + StringBuffer buf= new StringBuffer(); + buf.append(" [list change\n\t"); //$NON-NLS-1$ + + RewriteEvent[] events= getChildren(); + for (int i= 0; i < events.length; i++) { + if (i != 0) { + buf.append("\n\t"); //$NON-NLS-1$ + } + buf.append(events[i]); + } + buf.append("\n]"); //$NON-NLS-1$ + return buf.toString(); + } + + + +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/NodeInfoStore.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/NodeInfoStore.java new file mode 100644 index 000000000..6c03454cb --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/NodeInfoStore.java @@ -0,0 +1,163 @@ +/******************************************************************************* + * Copyright (c) 2000, 2009 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.core.dom.rewrite; + +import java.util.HashSet; +import java.util.IdentityHashMap; +import java.util.Map; +import java.util.Set; + +import org.eclipse.jdt.core.dom.AST; +import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.Block; +import org.eclipse.jdt.core.dom.FieldDeclaration; +import org.eclipse.jdt.core.dom.Modifier; +import org.eclipse.jdt.core.dom.ParameterizedType; +import org.eclipse.jdt.core.dom.TryStatement; +import org.eclipse.jdt.core.dom.VariableDeclarationExpression; +import org.eclipse.jdt.core.dom.VariableDeclarationStatement; + +import org.eclipse.jdt.internal.core.dom.rewrite.RewriteEventStore.CopySourceInfo; + +/** + * + */ +public final class NodeInfoStore { + private AST ast; + + private Map placeholderNodes; + private Set collapsedNodes; + + public NodeInfoStore(AST ast) { + super(); + this.ast= ast; + this.placeholderNodes= null; + this.collapsedNodes= null; + } + + /** + * Marks a node as a placehoder for a plain string content. The type of the node should correspond to the + * code's code content. + * @param placeholder The placeholder node that acts for the string content. + * @param code The string content. + */ + public final void markAsStringPlaceholder(ASTNode placeholder, String code) { + StringPlaceholderData data= new StringPlaceholderData(); + data.code= code; + setPlaceholderData(placeholder, data); + } + + /** + * Marks a node as a copy or move target. The copy target represents a copied node at the target (copied) site. + * @param target The node at the target site. Can be a placeholder node but also the source node itself. + * @param copySource The info at the source site. + */ + public final void markAsCopyTarget(ASTNode target, CopySourceInfo copySource) { + CopyPlaceholderData data= new CopyPlaceholderData(); + data.copySource= copySource; + setPlaceholderData(target, data); + } + + /** + * Creates a placeholder node of the given type. <code>null</code> if the type is not supported + * @param nodeType Type of the node to create. Use the type constants in {@link NodeInfoStore}. + * @return Returns a place holder node. + */ + public final ASTNode newPlaceholderNode(int nodeType) { + try { + ASTNode node= this.ast.createInstance(nodeType); + switch (node.getNodeType()) { + case ASTNode.FIELD_DECLARATION: + ((FieldDeclaration) node).fragments().add(this.ast.newVariableDeclarationFragment()); + break; + case ASTNode.MODIFIER: + ((Modifier) node).setKeyword(Modifier.ModifierKeyword.ABSTRACT_KEYWORD); + break; + case ASTNode.TRY_STATEMENT : + ((TryStatement) node).setFinally(this.ast.newBlock()); // have to set at least a finally block to be legal code + break; + case ASTNode.VARIABLE_DECLARATION_EXPRESSION : + ((VariableDeclarationExpression) node).fragments().add(this.ast.newVariableDeclarationFragment()); + break; + case ASTNode.VARIABLE_DECLARATION_STATEMENT : + ((VariableDeclarationStatement) node).fragments().add(this.ast.newVariableDeclarationFragment()); + break; + case ASTNode.PARAMETERIZED_TYPE : + ((ParameterizedType) node).typeArguments().add(this.ast.newWildcardType()); + break; + } + return node; + } catch (IllegalArgumentException e) { + return null; + } + } + + + // collapsed nodes: in source: use one node that represents many; to be used as + // copy/move source or to replace at once. + // in the target: one block node that is not flattened. + + public Block createCollapsePlaceholder() { + Block placeHolder= this.ast.newBlock(); + if (this.collapsedNodes == null) { + this.collapsedNodes= new HashSet(); + } + this.collapsedNodes.add(placeHolder); + return placeHolder; + } + + public boolean isCollapsed(ASTNode node) { + if (this.collapsedNodes != null) { + return this.collapsedNodes.contains(node); + } + return false; + } + + public Object getPlaceholderData(ASTNode node) { + if (this.placeholderNodes != null) { + return this.placeholderNodes.get(node); + } + return null; + } + + private void setPlaceholderData(ASTNode node, PlaceholderData data) { + if (this.placeholderNodes == null) { + this.placeholderNodes= new IdentityHashMap(); + } + this.placeholderNodes.put(node, data); + } + + static class PlaceholderData { + // base class + } + + protected static final class CopyPlaceholderData extends PlaceholderData { + public CopySourceInfo copySource; + public String toString() { + return "[placeholder " + this.copySource +"]"; //$NON-NLS-1$//$NON-NLS-2$ + } + } + + protected static final class StringPlaceholderData extends PlaceholderData { + public String code; + public String toString() { + return "[placeholder string: " + this.code +"]"; //$NON-NLS-1$ //$NON-NLS-2$ + } + } + + /** + * + */ + public void clear() { + this.placeholderNodes= null; + this.collapsedNodes= null; + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/NodeRewriteEvent.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/NodeRewriteEvent.java new file mode 100644 index 000000000..cb063ebb7 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/NodeRewriteEvent.java @@ -0,0 +1,114 @@ +/******************************************************************************* + * Copyright (c) 2000, 2009 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.core.dom.rewrite; + + + +/** + * + */ +public class NodeRewriteEvent extends RewriteEvent { + + private Object originalValue; + private Object newValue; + + public NodeRewriteEvent(Object originalValue, Object newValue) { + this.originalValue= originalValue; + this.newValue= newValue; + } + + /** + * @return Returns the new value. + */ + public Object getNewValue() { + return this.newValue; + } + + /** + * @return Returns the original value. + */ + public Object getOriginalValue() { + return this.originalValue; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.corext.dom.RewriteEvent#getChangeKind() + */ + public int getChangeKind() { + if (this.originalValue == this.newValue) { + return UNCHANGED; + } + if (this.originalValue == null) { + return INSERTED; + } + if (this.newValue == null) { + return REMOVED; + } + if (this.originalValue.equals(this.newValue)) { + return UNCHANGED; + } + return REPLACED; + } + + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.corext.dom.RewriteEvent#isListRewrite() + */ + public boolean isListRewrite() { + return false; + } + + /* + * Sets a new value for the new node. Internal access only. + * @param newValue The new value to set. + */ + public void setNewValue(Object newValue) { + this.newValue= newValue; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.corext.dom.RewriteEvent#getChildren() + */ + public RewriteEvent[] getChildren() { + return null; + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + public String toString() { + StringBuffer buf= new StringBuffer(); + switch (getChangeKind()) { + case INSERTED: + buf.append(" [inserted: "); //$NON-NLS-1$ + buf.append(getNewValue()); + buf.append(']'); + break; + case REPLACED: + buf.append(" [replaced: "); //$NON-NLS-1$ + buf.append(getOriginalValue()); + buf.append(" -> "); //$NON-NLS-1$ + buf.append(getNewValue()); + buf.append(']'); + break; + case REMOVED: + buf.append(" [removed: "); //$NON-NLS-1$ + buf.append(getOriginalValue()); + buf.append(']'); + break; + default: + buf.append(" [unchanged]"); //$NON-NLS-1$ + } + return buf.toString(); + } + + +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/RewriteEvent.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/RewriteEvent.java new file mode 100644 index 000000000..e957b360b --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/RewriteEvent.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2000, 2009 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.core.dom.rewrite; + + +/** + * + */ +public abstract class RewriteEvent { + + /** + * Change kind to describe that the event is an insert event. + * Does not apply for list events. + */ + public static final int INSERTED= 1; + + /** + * Change kind to describe that the event is an remove event. + * Does not apply for list events. + */ + public static final int REMOVED= 2; + + /** + * Change kind to describe that the event is an replace event. + * Does not apply for list events. + */ + public static final int REPLACED= 4; + + /** + * Change kind to signal that children changed. Does only apply for list events. + */ + public static final int CHILDREN_CHANGED= 8; + + /** + * Change kind to signal that the property did not change + */ + public static final int UNCHANGED= 0; + + /** + * @return Returns the event's change kind. + */ + public abstract int getChangeKind(); + + /** + * @return Returns true if the given event is a list event. + */ + public abstract boolean isListRewrite(); + + /** + * @return Returns the original value. For lists this is a <code>List<code> of ASTNode's, for non-list + * events this can be an ASTNode (for node properties), Integer (for an integer property), + * Boolean (for boolean node properties) or properties like Operator. + * <code>null</code> is returned if the event is a insert event. + */ + public abstract Object getOriginalValue(); + + /** + * @return Returns the new value. For lists this is a <code>List<code> of ASTNode's, for non-list + * events this can be an ASTNode (for node properties), Integer (for an integer property), + * Boolean (for boolean node properties) or properties like Operator. + * <code>null</code> is returned if the event is a remove event. + */ + public abstract Object getNewValue(); + + /** + * @return Return the events describing the changes in a list. returns <code>null</code> if the + * event is not a list event. + */ + public abstract RewriteEvent[] getChildren(); + +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/RewriteEventStore.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/RewriteEventStore.java new file mode 100644 index 000000000..7b0d5974d --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/RewriteEventStore.java @@ -0,0 +1,872 @@ +/******************************************************************************* + * Copyright (c) 2000, 2009 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.core.dom.rewrite; + +import java.util.*; + +import org.eclipse.jdt.core.Signature; +import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.Block; +import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor; +import org.eclipse.jdt.core.dom.rewrite.TargetSourceRangeComputer; +import org.eclipse.text.edits.TextEditGroup; + + +/** + * Stores all rewrite events, descriptions of events and knows which nodes + * are copy or move sources or tracked. + */ +public final class RewriteEventStore { + + + public static final class PropertyLocation { + private final ASTNode parent; + private final StructuralPropertyDescriptor property; + + public PropertyLocation(ASTNode parent, StructuralPropertyDescriptor property) { + this.parent= parent; + this.property= property; + } + + public ASTNode getParent() { + return this.parent; + } + + public StructuralPropertyDescriptor getProperty() { + return this.property; + } + + public boolean equals(Object obj) { + if (obj != null && obj.getClass().equals(getClass())) { + PropertyLocation other= (PropertyLocation) obj; + return other.getParent().equals(getParent()) && other.getProperty().equals(getProperty()); + } + return false; + } + + public int hashCode() { + return getParent().hashCode() + getProperty().hashCode(); + } + + } + + /** + * Interface that allows to override the way how children are accessed from + * a parent. Use this interface when the rewriter is set up on an already + * modified AST's (as it is the case in the old ASTRewrite infrastructure) + */ + public static interface INodePropertyMapper { + /** + * Returns the node attribute for a given property name. + * @param parent The parent node + * @param childProperty The child property to access + * @return The child node at the given property location. + */ + Object getOriginalValue(ASTNode parent, StructuralPropertyDescriptor childProperty); + } + + /* + * Store element to associate event and node position/ + */ + private static class EventHolder { + public final ASTNode parent; + public final StructuralPropertyDescriptor childProperty; + public final RewriteEvent event; + + public EventHolder(ASTNode parent, StructuralPropertyDescriptor childProperty, RewriteEvent change) { + this.parent= parent; + this.childProperty= childProperty; + this.event= change; + } + + public String toString() { + StringBuffer buf= new StringBuffer(); + buf.append(this.parent).append(" - "); //$NON-NLS-1$ + buf.append(this.childProperty.getId()).append(": "); //$NON-NLS-1$ + buf.append(this.event).append('\n'); + return buf.toString(); + } + } + + public static class CopySourceInfo implements Comparable { + public final PropertyLocation location; // can be null, only used to mark as removed on move + private final ASTNode node; + public final boolean isMove; + + public CopySourceInfo(PropertyLocation location, ASTNode node, boolean isMove) { + this.location= location; + this.node= node; + this.isMove= isMove; + } + + public ASTNode getNode() { + return this.node; + } + + public int compareTo(Object o2) { + CopySourceInfo r2= (CopySourceInfo) o2; + + int startDiff= getNode().getStartPosition() - r2.getNode().getStartPosition(); + if (startDiff != 0) { + return startDiff; // insert before if start node is first + } + + if (r2.isMove != this.isMove) { + return this.isMove ? -1 : 1; // first move then copy + } + return 0; + } + + public String toString() { + StringBuffer buf= new StringBuffer(); + if (this.isMove) { + buf.append("move source: "); //$NON-NLS-1$ + } else { + buf.append("copy source: "); //$NON-NLS-1$ + } + buf.append(this.node); + return buf.toString(); + } + } + + private static class NodeRangeInfo implements Comparable { + private final ASTNode first; + private final ASTNode last; + public final CopySourceInfo copyInfo; // containing the internal placeholder and the 'isMove' flag + public final ASTNode replacingNode; + public final TextEditGroup editGroup; + + public NodeRangeInfo(ASTNode parent, StructuralPropertyDescriptor childProperty, ASTNode first, ASTNode last, CopySourceInfo copyInfo, ASTNode replacingNode, TextEditGroup editGroup) { + this.first= first; + this.last= last; + this.copyInfo= copyInfo; + this.replacingNode= replacingNode; + this.editGroup= editGroup; + } + + public ASTNode getStartNode() { + return this.first; + } + + public ASTNode getEndNode() { + return this.last; + } + + public boolean isMove() { + return this.copyInfo.isMove; + } + + public Block getInternalPlaceholder() { + return (Block) this.copyInfo.getNode(); + } + + public int compareTo(Object o2) { + NodeRangeInfo r2= (NodeRangeInfo) o2; + + int startDiff= getStartNode().getStartPosition() - r2.getStartNode().getStartPosition(); + if (startDiff != 0) { + return startDiff; // insert before if start node is first + } + int endDiff= getEndNode().getStartPosition() - r2.getEndNode().getStartPosition(); + if (endDiff != 0) { + return -endDiff; // insert before if length is longer + } + if (r2.isMove() != isMove()) { + return isMove() ? -1 : 1; // first move then copy + } + return 0; + } + + public void updatePlaceholderSourceRanges(TargetSourceRangeComputer sourceRangeComputer) { + TargetSourceRangeComputer.SourceRange startRange= sourceRangeComputer.computeSourceRange(getStartNode()); + TargetSourceRangeComputer.SourceRange endRange= sourceRangeComputer.computeSourceRange(getEndNode()); + int startPos= startRange.getStartPosition(); + int endPos= endRange.getStartPosition() + endRange.getLength(); + + Block internalPlaceholder= getInternalPlaceholder(); + internalPlaceholder.setSourceRange(startPos, endPos - startPos); + } + + public String toString() { + StringBuffer buf= new StringBuffer(); + if (this.first != this.last) { + buf.append("range "); //$NON-NLS-1$ + } + if (isMove()) { + buf.append("move source: "); //$NON-NLS-1$ + } else { + buf.append("copy source: "); //$NON-NLS-1$ + } + buf.append(this.first); + buf.append(" - "); //$NON-NLS-1$ + buf.append(this.last); + return buf.toString(); + } + + + } + + /** + * Iterates over all event parent nodes, tracked nodes and all copy/move sources + */ + private class ParentIterator implements Iterator { + + private Iterator eventIter; + private Iterator sourceNodeIter; + private Iterator rangeNodeIter; + private Iterator trackedNodeIter; + + public ParentIterator() { + this.eventIter= RewriteEventStore.this.eventLookup.keySet().iterator(); + if (RewriteEventStore.this.nodeCopySources != null) { + this.sourceNodeIter= RewriteEventStore.this.nodeCopySources.iterator(); + } else { + this.sourceNodeIter= Collections.EMPTY_LIST.iterator(); + } + if (RewriteEventStore.this.nodeRangeInfos != null) { + this.rangeNodeIter= RewriteEventStore.this.nodeRangeInfos.keySet().iterator(); + } else { + this.rangeNodeIter= Collections.EMPTY_LIST.iterator(); + } + if (RewriteEventStore.this.trackedNodes != null) { + this.trackedNodeIter= RewriteEventStore.this.trackedNodes.keySet().iterator(); + } else { + this.trackedNodeIter= Collections.EMPTY_LIST.iterator(); + } + } + + /* (non-Javadoc) + * @see java.util.Iterator#hasNext() + */ + public boolean hasNext() { + return this.eventIter.hasNext() || this.sourceNodeIter.hasNext() || this.rangeNodeIter.hasNext() || this.trackedNodeIter.hasNext(); + } + + /* (non-Javadoc) + * @see java.util.Iterator#next() + */ + public Object next() { + if (this.eventIter.hasNext()) { + return this.eventIter.next(); + } + if (this.sourceNodeIter.hasNext()) { + return ((CopySourceInfo) this.sourceNodeIter.next()).getNode(); + } + if (this.rangeNodeIter.hasNext()) { + return ((PropertyLocation) this.rangeNodeIter.next()).getParent(); + } + return this.trackedNodeIter.next(); + } + + /* (non-Javadoc) + * @see java.util.Iterator#remove() + */ + public void remove() { + throw new UnsupportedOperationException(); + } + } + + public final static int NEW= 1; + public final static int ORIGINAL= 2; + public final static int BOTH= NEW | ORIGINAL; + + + /** all events by parent*/ + final Map eventLookup; + + /** cache for last accessed event */ + private EventHolder lastEvent; + + /** Maps events to group descriptions */ + private Map editGroups; + + /** Stores which nodes are source of a copy or move (list of CopySourceInfo)*/ + List nodeCopySources; + + /** Stores node ranges that are used to copy or move (map of <PropertyLocation, CopyRangeInfo>)*/ + Map nodeRangeInfos; + + /** Stores which nodes are tracked and the corresponding edit group*/ + Map trackedNodes; + + /** Stores which inserted nodes bound to the previous node. If not, a node is + * always bound to the next node */ + private Set insertBoundToPrevious; + + /** optional mapper to allow fix already modified AST trees */ + private INodePropertyMapper nodePropertyMapper; + + private static final String INTERNAL_PLACEHOLDER_PROPERTY= "rewrite_internal_placeholder"; //$NON-NLS-1$ + + public RewriteEventStore() { + this.eventLookup= new HashMap(); + this.lastEvent= null; + + this.editGroups= null; // lazy initialization + + this.trackedNodes= null; + this.insertBoundToPrevious= null; + + this.nodePropertyMapper= null; + this.nodeCopySources= null; + this.nodeRangeInfos= null; + } + + /** + * Override the default way how to access children from a parent node. + * @param nodePropertyMapper The new <code>INodePropertyMapper</code> or + * <code>null</code>. to use the default. + */ + public void setNodePropertyMapper(INodePropertyMapper nodePropertyMapper) { + this.nodePropertyMapper= nodePropertyMapper; + } + + public void clear() { + this.eventLookup.clear(); + this.lastEvent= null; + this.trackedNodes= null; + + this.editGroups= null; // lazy initialization + this.insertBoundToPrevious= null; + this.nodeCopySources= null; + } + + public void addEvent(ASTNode parent, StructuralPropertyDescriptor childProperty, RewriteEvent event) { + validateHasChildProperty(parent, childProperty); + + if (event.isListRewrite()) { + validateIsListProperty(childProperty); + } + + EventHolder holder= new EventHolder(parent, childProperty, event); + + List entriesList = (List) this.eventLookup.get(parent); + if (entriesList != null) { + for (int i= 0; i < entriesList.size(); i++) { + EventHolder curr= (EventHolder) entriesList.get(i); + if (curr.childProperty == childProperty) { + entriesList.set(i, holder); + this.lastEvent= null; + return; + } + } + } else { + entriesList= new ArrayList(3); + this.eventLookup.put(parent, entriesList); + } + entriesList.add(holder); + } + + public RewriteEvent getEvent(ASTNode parent, StructuralPropertyDescriptor property) { + validateHasChildProperty(parent, property); + + if (this.lastEvent != null && this.lastEvent.parent == parent && this.lastEvent.childProperty == property) { + return this.lastEvent.event; + } + + List entriesList = (List) this.eventLookup.get(parent); + if (entriesList != null) { + for (int i= 0; i < entriesList.size(); i++) { + EventHolder holder= (EventHolder) entriesList.get(i); + if (holder.childProperty == property) { + this.lastEvent= holder; + return holder.event; + } + } + } + return null; + } + + public NodeRewriteEvent getNodeEvent(ASTNode parent, StructuralPropertyDescriptor childProperty, boolean forceCreation) { + validateIsNodeProperty(childProperty); + NodeRewriteEvent event= (NodeRewriteEvent) getEvent(parent, childProperty); + if (event == null && forceCreation) { + Object originalValue= accessOriginalValue(parent, childProperty); + event= new NodeRewriteEvent(originalValue, originalValue); + addEvent(parent, childProperty, event); + } + return event; + } + + public ListRewriteEvent getListEvent(ASTNode parent, StructuralPropertyDescriptor childProperty, boolean forceCreation) { + validateIsListProperty(childProperty); + ListRewriteEvent event= (ListRewriteEvent) getEvent(parent, childProperty); + if (event == null && forceCreation) { + List originalValue= (List) accessOriginalValue(parent, childProperty); + event= new ListRewriteEvent(originalValue); + addEvent(parent, childProperty, event); + } + return event; + } + + public Iterator getChangeRootIterator() { + return new ParentIterator(); + } + + + public boolean hasChangedProperties(ASTNode parent) { + List entriesList = (List) this.eventLookup.get(parent); + if (entriesList != null) { + for (int i= 0; i < entriesList.size(); i++) { + EventHolder holder= (EventHolder) entriesList.get(i); + if (holder.event.getChangeKind() != RewriteEvent.UNCHANGED) { + return true; + } + } + } + return false; + } + + public PropertyLocation getPropertyLocation(Object value, int kind) { + for (Iterator iter= this.eventLookup.values().iterator(); iter.hasNext();) { + List events= (List) iter.next(); + for (int i= 0; i < events.size(); i++) { + EventHolder holder= (EventHolder) events.get(i); + RewriteEvent event= holder.event; + if (isNodeInEvent(event, value, kind)) { + return new PropertyLocation(holder.parent, holder.childProperty); + } + if (event.isListRewrite()) { + RewriteEvent[] children= event.getChildren(); + for (int k= 0; k < children.length; k++) { + if (isNodeInEvent(children[k], value, kind)) { + return new PropertyLocation(holder.parent, holder.childProperty); + } + } + } + } + } + if (value instanceof ASTNode) { + ASTNode node= (ASTNode) value; + return new PropertyLocation(node.getParent(), node.getLocationInParent()); + } + return null; + } + + + /** + * Kind is either ORIGINAL, NEW, or BOTH + * @param value + * @param kind + * @return Returns the event with the given value of <code>null</code>. + */ + public RewriteEvent findEvent(Object value, int kind) { + for (Iterator iter= this.eventLookup.values().iterator(); iter.hasNext();) { + List events= (List) iter.next(); + for (int i= 0; i < events.size(); i++) { + RewriteEvent event= ((EventHolder) events.get(i)).event; + if (isNodeInEvent(event, value, kind)) { + return event; + } + if (event.isListRewrite()) { + RewriteEvent[] children= event.getChildren(); + for (int k= 0; k < children.length; k++) { + if (isNodeInEvent(children[k], value, kind)) { + return children[k]; + } + } + } + } + } + return null; + } + + private boolean isNodeInEvent(RewriteEvent event, Object value, int kind) { + if (((kind & NEW) != 0) && event.getNewValue() == value) { + return true; + } + if (((kind & ORIGINAL) != 0) && event.getOriginalValue() == value) { + return true; + } + return false; + } + + + public Object getOriginalValue(ASTNode parent, StructuralPropertyDescriptor property) { + RewriteEvent event= getEvent(parent, property); + if (event != null) { + return event.getOriginalValue(); + } + return accessOriginalValue(parent, property); + } + + public Object getNewValue(ASTNode parent, StructuralPropertyDescriptor property) { + RewriteEvent event= getEvent(parent, property); + if (event != null) { + return event.getNewValue(); + } + return accessOriginalValue(parent, property); + } + + public List getChangedPropertieEvents(ASTNode parent) { + List changedPropertiesEvent = new ArrayList(); + + List entriesList = (List) this.eventLookup.get(parent); + if (entriesList != null) { + for (int i= 0; i < entriesList.size(); i++) { + EventHolder holder= (EventHolder) entriesList.get(i); + if (holder.event.getChangeKind() != RewriteEvent.UNCHANGED) { + changedPropertiesEvent.add(holder.event); + } + } + } + return changedPropertiesEvent; + } + + public int getChangeKind(ASTNode node) { + RewriteEvent event= findEvent(node, ORIGINAL); + if (event != null) { + return event.getChangeKind(); + } + return RewriteEvent.UNCHANGED; + } + + /* + * Gets an original child from the AST. + * Temporarily overridden to port the old rewriter to the new infrastructure. + */ + private Object accessOriginalValue(ASTNode parent, StructuralPropertyDescriptor childProperty) { + if (this.nodePropertyMapper != null) { + return this.nodePropertyMapper.getOriginalValue(parent, childProperty); + } + + return parent.getStructuralProperty(childProperty); + } + + public TextEditGroup getEventEditGroup(RewriteEvent event) { + if (this.editGroups == null) { + return null; + } + return (TextEditGroup) this.editGroups.get(event); + } + + public void setEventEditGroup(RewriteEvent event, TextEditGroup editGroup) { + if (this.editGroups == null) { + this.editGroups= new IdentityHashMap(5); + } + this.editGroups.put(event, editGroup); + } + + + public final TextEditGroup getTrackedNodeData(ASTNode node) { + if (this.trackedNodes != null) { + return (TextEditGroup) this.trackedNodes.get(node); + } + return null; + } + + public void setTrackedNodeData(ASTNode node, TextEditGroup editGroup) { + if (this.trackedNodes == null) { + this.trackedNodes= new IdentityHashMap(); + } + this.trackedNodes.put(node, editGroup); + } + + /** + * Marks a node as tracked. The edits added to the group editGroup can be used to get the + * position of the node after the rewrite operation. + * @param node The node to track + * @param editGroup Collects the range markers describing the node position. + */ + public final void markAsTracked(ASTNode node, TextEditGroup editGroup) { + if (getTrackedNodeData(node) != null) { + throw new IllegalArgumentException("Node is already marked as tracked"); //$NON-NLS-1$ + } + setTrackedNodeData(node, editGroup); + } + + private final CopySourceInfo createCopySourceInfo(PropertyLocation location, ASTNode node, boolean isMove) { + CopySourceInfo copySource= new CopySourceInfo(location, node, isMove); + + if (this.nodeCopySources == null) { + this.nodeCopySources= new ArrayList(); + } + this.nodeCopySources.add(copySource); + return copySource; + } + + public final CopySourceInfo markAsCopySource(ASTNode parent, StructuralPropertyDescriptor property, ASTNode node, boolean isMove) { + return createCopySourceInfo(new PropertyLocation(parent, property), node, isMove); + } + + public final boolean isRangeCopyPlaceholder(ASTNode node) { + return node.getProperty(INTERNAL_PLACEHOLDER_PROPERTY) != null; + } + + public final CopySourceInfo createRangeCopy(ASTNode parent, StructuralPropertyDescriptor childProperty, ASTNode first, ASTNode last, boolean isMove, ASTNode internalPlaceholder, ASTNode replacingNode, TextEditGroup editGroup) { + CopySourceInfo copyInfo= createCopySourceInfo(null, internalPlaceholder, isMove); + internalPlaceholder.setProperty(INTERNAL_PLACEHOLDER_PROPERTY, internalPlaceholder); + + NodeRangeInfo copyRangeInfo= new NodeRangeInfo(parent, childProperty, first, last, copyInfo, replacingNode, editGroup); + + ListRewriteEvent listEvent= getListEvent(parent, childProperty, true); + + int indexFirst= listEvent.getIndex(first, ListRewriteEvent.OLD); + if (indexFirst == -1) { + throw new IllegalArgumentException("Start node is not a original child of the given list"); //$NON-NLS-1$ + } + int indexLast= listEvent.getIndex(last, ListRewriteEvent.OLD); + if (indexLast == -1) { + throw new IllegalArgumentException("End node is not a original child of the given list"); //$NON-NLS-1$ + } + + if (indexFirst > indexLast) { + throw new IllegalArgumentException("Start node must be before end node"); //$NON-NLS-1$ + } + + if (this.nodeRangeInfos == null) { + this.nodeRangeInfos= new HashMap(); + } + PropertyLocation loc= new PropertyLocation(parent, childProperty); + List innerList= (List) this.nodeRangeInfos.get(loc); + if (innerList == null) { + innerList= new ArrayList(2); + this.nodeRangeInfos.put(loc, innerList); + } else { + assertNoOverlap(listEvent, indexFirst, indexLast, innerList); + } + innerList.add(copyRangeInfo); + + + return copyInfo; + } + + public CopySourceInfo[] getNodeCopySources(ASTNode node) { + if (this.nodeCopySources == null) { + return null; + } + return internalGetCopySources(this.nodeCopySources, node); + } + + + public CopySourceInfo[] internalGetCopySources(List copySources, ASTNode node) { + ArrayList res= new ArrayList(3); + for (int i= 0; i < copySources.size(); i++) { + CopySourceInfo curr= (CopySourceInfo) copySources.get(i); + if (curr.getNode() == node) { + res.add(curr); + } + } + if (res.isEmpty()) { + return null; + } + + CopySourceInfo[] arr= (CopySourceInfo[]) res.toArray(new CopySourceInfo[res.size()]); + Arrays.sort(arr); + return arr; + } + + + private void assertNoOverlap(ListRewriteEvent listEvent, int indexFirst, int indexLast, List innerList) { + for (Iterator iter= innerList.iterator(); iter.hasNext();) { + NodeRangeInfo curr= (NodeRangeInfo) iter.next(); + int currStart= listEvent.getIndex(curr.getStartNode(), ListRewriteEvent.BOTH); + int currEnd= listEvent.getIndex(curr.getEndNode(), ListRewriteEvent.BOTH); + if (currStart < indexFirst && currEnd < indexLast && currEnd >= indexFirst + || currStart > indexFirst && currStart <= currEnd && currEnd > indexLast) { + throw new IllegalArgumentException("Range overlapps with an existing copy or move range"); //$NON-NLS-1$ + } + } + } + + public void prepareMovedNodes(TargetSourceRangeComputer sourceRangeComputer) { + if (this.nodeCopySources != null) { + prepareSingleNodeCopies(); + } + + if (this.nodeRangeInfos != null) { + prepareNodeRangeCopies(sourceRangeComputer); + } + } + + public void revertMovedNodes() { + if (this.nodeRangeInfos != null) { + removeMoveRangePlaceholders(); + } + } + + private void removeMoveRangePlaceholders() { + for (Iterator iter= this.nodeRangeInfos.entrySet().iterator(); iter.hasNext();) { + Map.Entry entry= (Map.Entry) iter.next(); + Set placeholders= new HashSet(); // collect all placeholders + List rangeInfos= (List) entry.getValue(); // list of CopySourceRange + for (int i= 0; i < rangeInfos.size(); i++) { + placeholders.add(((NodeRangeInfo) rangeInfos.get(i)).getInternalPlaceholder()); + } + + PropertyLocation loc= (PropertyLocation) entry.getKey(); + + RewriteEvent[] children= getListEvent(loc.getParent(), loc.getProperty(), true).getChildren(); + List revertedChildren= new ArrayList(); + revertListWithRanges(children, placeholders, revertedChildren); + RewriteEvent[] revertedChildrenArr= (RewriteEvent[]) revertedChildren.toArray(new RewriteEvent[revertedChildren.size()]); + addEvent(loc.getParent(), loc.getProperty(), new ListRewriteEvent(revertedChildrenArr)); // replace the current edits + } + } + + private void revertListWithRanges(RewriteEvent[] childEvents, Set placeholders, List revertedChildren) { + for (int i= 0; i < childEvents.length; i++) { + RewriteEvent event= childEvents[i]; + ASTNode node= (ASTNode) event.getOriginalValue(); + if (placeholders.contains(node)) { + RewriteEvent[] placeholderChildren= getListEvent(node, Block.STATEMENTS_PROPERTY, false).getChildren(); + revertListWithRanges(placeholderChildren, placeholders, revertedChildren); + } else { + revertedChildren.add(event); + } + } + } + + private void prepareNodeRangeCopies(TargetSourceRangeComputer sourceRangeComputer) { + for (Iterator iter= this.nodeRangeInfos.entrySet().iterator(); iter.hasNext();) { + Map.Entry entry= (Map.Entry) iter.next(); + List rangeInfos= (List) entry.getValue(); // list of CopySourceRange + Collections.sort(rangeInfos); // sort by start index, length, move or copy + + PropertyLocation loc= (PropertyLocation) entry.getKey(); + RewriteEvent[] children= getListEvent(loc.getParent(), loc.getProperty(), true).getChildren(); + + RewriteEvent[] newChildren= processListWithRanges(rangeInfos, children, sourceRangeComputer); + addEvent(loc.getParent(), loc.getProperty(), new ListRewriteEvent(newChildren)); // replace the current edits + } + } + + private RewriteEvent[] processListWithRanges(List rangeInfos, RewriteEvent[] childEvents, TargetSourceRangeComputer sourceRangeComputer) { + List newChildEvents= new ArrayList(childEvents.length); + NodeRangeInfo topInfo= null; + Stack newChildrenStack= new Stack(); + Stack topInfoStack= new Stack(); + + Iterator rangeInfoIterator= rangeInfos.iterator(); + NodeRangeInfo nextInfo= (NodeRangeInfo) rangeInfoIterator.next(); + + for (int k= 0; k < childEvents.length; k++) { + RewriteEvent event= childEvents[k]; + ASTNode node= (ASTNode) event.getOriginalValue(); + // check for ranges and add a placeholder for them + while (nextInfo != null && node == nextInfo.getStartNode()) { // is this child the beginning of a range? + nextInfo.updatePlaceholderSourceRanges(sourceRangeComputer); + + Block internalPlaceholder= nextInfo.getInternalPlaceholder(); + RewriteEvent newEvent; + if (nextInfo.isMove()) { + newEvent= new NodeRewriteEvent(internalPlaceholder, nextInfo.replacingNode); // remove or replace + } else { + newEvent= new NodeRewriteEvent(internalPlaceholder, internalPlaceholder); // unchanged + } + newChildEvents.add(newEvent); + if (nextInfo.editGroup != null) { + setEventEditGroup(newEvent, nextInfo.editGroup); + } + + newChildrenStack.push(newChildEvents); + topInfoStack.push(topInfo); + + newChildEvents= new ArrayList(childEvents.length); + topInfo= nextInfo; + + nextInfo= rangeInfoIterator.hasNext() ? (NodeRangeInfo) rangeInfoIterator.next() : null; + } + + newChildEvents.add(event); + + while (topInfo != null && node == topInfo.getEndNode()) { + RewriteEvent[] placeholderChildEvents= (RewriteEvent[]) newChildEvents.toArray(new RewriteEvent[newChildEvents.size()]); + Block internalPlaceholder= topInfo.getInternalPlaceholder(); + addEvent(internalPlaceholder, Block.STATEMENTS_PROPERTY, new ListRewriteEvent(placeholderChildEvents)); + + newChildEvents= (List) newChildrenStack.pop(); + topInfo= (NodeRangeInfo) topInfoStack.pop(); + } + } + return (RewriteEvent[]) newChildEvents.toArray(new RewriteEvent[newChildEvents.size()]); + } + + /** + * Make sure all moved nodes are marked as removed or replaced. + */ + private void prepareSingleNodeCopies() { + for (int i= 0; i < this.nodeCopySources.size(); i++) { + CopySourceInfo curr= (CopySourceInfo) this.nodeCopySources.get(i); + if (curr.isMove && curr.location != null) { + doMarkMovedAsRemoved(curr, curr.location.getParent(), curr.location.getProperty()); + } + } + + } + + private void doMarkMovedAsRemoved(CopySourceInfo curr, ASTNode parent, StructuralPropertyDescriptor childProperty) { + if (childProperty.isChildListProperty()) { + ListRewriteEvent event= getListEvent(parent, childProperty, true); + int index= event.getIndex(curr.getNode(), ListRewriteEvent.OLD); + if (index != -1 && event.getChangeKind(index) == RewriteEvent.UNCHANGED) { + event.setNewValue(null, index); + } + } else { + NodeRewriteEvent event= getNodeEvent(parent, childProperty, true); + if (event.getChangeKind() == RewriteEvent.UNCHANGED) { + event.setNewValue(null); + } + } + } + + public boolean isInsertBoundToPrevious(ASTNode node) { + if (this.insertBoundToPrevious != null) { + return this.insertBoundToPrevious.contains(node); + } + return false; + } + + public void setInsertBoundToPrevious(ASTNode node) { + if (this.insertBoundToPrevious == null) { + this.insertBoundToPrevious= new HashSet(); + } + this.insertBoundToPrevious.add(node); + } + + private void validateIsListProperty(StructuralPropertyDescriptor property) { + if (!property.isChildListProperty()) { + String message= property.getId() + " is not a list property"; //$NON-NLS-1$ + throw new IllegalArgumentException(message); + } + } + + private void validateHasChildProperty(ASTNode parent, StructuralPropertyDescriptor property) { + if (!parent.structuralPropertiesForType().contains(property)) { + String message= Signature.getSimpleName(parent.getClass().getName()) + " has no property " + property.getId(); //$NON-NLS-1$ + throw new IllegalArgumentException(message); + } + } + + private void validateIsNodeProperty(StructuralPropertyDescriptor property) { + if (property.isChildListProperty()) { + String message= property.getId() + " is not a node property"; //$NON-NLS-1$ + throw new IllegalArgumentException(message); + } + } + + public String toString() { + StringBuffer buf= new StringBuffer(); + for (Iterator iter = this.eventLookup.values().iterator(); iter.hasNext();) { + List events = (List) iter.next(); + for (int i= 0; i < events.size(); i++) { + buf.append(events.get(i).toString()).append('\n'); + } + } + return buf.toString(); + } + + public static boolean isNewNode(ASTNode node) { + return (node.getFlags() & ASTNode.ORIGINAL) == 0; + } + + +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/SourceModifier.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/SourceModifier.java new file mode 100644 index 000000000..9e83303b6 --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/SourceModifier.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2000, 2009 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.core.dom.rewrite; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jdt.core.formatter.IndentManipulation; +import org.eclipse.text.edits.ISourceModifier; +import org.eclipse.text.edits.ReplaceEdit; + + +public class SourceModifier implements ISourceModifier { + + private final String destinationIndent; + private final int sourceIndentLevel; + private final int tabWidth; + private final int indentWidth; + + public SourceModifier(int sourceIndentLevel, String destinationIndent, int tabWidth, int indentWidth) { + this.destinationIndent= destinationIndent; + this.sourceIndentLevel= sourceIndentLevel; + this.tabWidth= tabWidth; + this.indentWidth= indentWidth; + } + + public ISourceModifier copy() { + // We are state less + return this; + } + + public ReplaceEdit[] getModifications(String source) { + List result= new ArrayList(); + int destIndentLevel= IndentManipulation.measureIndentUnits(this.destinationIndent, this.tabWidth, this.indentWidth); + if (destIndentLevel == this.sourceIndentLevel) { + return (ReplaceEdit[])result.toArray(new ReplaceEdit[result.size()]); + } + return IndentManipulation.getChangeIndentEdits(source, this.sourceIndentLevel, this.tabWidth, this.indentWidth, this.destinationIndent); + } +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/TokenScanner.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/TokenScanner.java new file mode 100644 index 000000000..344272b7d --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/TokenScanner.java @@ -0,0 +1,238 @@ +/******************************************************************************* + * Copyright (c) 2000, 2009 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.core.dom.rewrite; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.compiler.InvalidInputException; +import org.eclipse.jdt.internal.compiler.parser.Scanner; +import org.eclipse.jdt.internal.compiler.parser.TerminalTokens; + +/** + * Wraps a scanner and offers convenient methods for finding tokens + */ +public class TokenScanner { + + public static final int END_OF_FILE= 20001; + public static final int LEXICAL_ERROR= 20002; + public static final int DOCUMENT_ERROR= 20003; + + private final Scanner scanner; + private final int endPosition; + + /** + * Creates a TokenScanner + * @param scanner The scanner to be wrapped + */ + public TokenScanner(Scanner scanner) { + this.scanner= scanner; + this.endPosition= this.scanner.getSource().length - 1; + } + + /** + * Returns the wrapped scanner + * @return IScanner + */ + public Scanner getScanner() { + return this.scanner; + } + + /** + * Sets the scanner offset to the given offset. + * @param offset The offset to set + */ + public void setOffset(int offset) { + this.scanner.resetTo(offset, this.endPosition); + } + + /** + * @return Returns the offset after the current token + */ + public int getCurrentEndOffset() { + return this.scanner.getCurrentTokenEndPosition() + 1; + } + + /** + * @return Returns the start offset of the current token + */ + public int getCurrentStartOffset() { + return this.scanner.getCurrentTokenStartPosition(); + } + + /** + * @return Returns the length of the current token + */ + public int getCurrentLength() { + return getCurrentEndOffset() - getCurrentStartOffset(); + } + + /** + * Reads the next token. + * @param ignoreComments If set, comments will be overread + * @return Return the token id. + * @exception CoreException Thrown when the end of the file has been reached (code END_OF_FILE) + * or a lexical error was detected while scanning (code LEXICAL_ERROR) + */ + public int readNext(boolean ignoreComments) throws CoreException { + int curr= 0; + do { + try { + curr= this.scanner.getNextToken(); + if (curr == TerminalTokens.TokenNameEOF) { + throw new CoreException(createError(END_OF_FILE, "End Of File", null)); //$NON-NLS-1$ + } + } catch (InvalidInputException e) { + throw new CoreException(createError(LEXICAL_ERROR, e.getMessage(), e)); + } + } while (ignoreComments && isComment(curr)); + return curr; + } + + /** + * Reads the next token from the given offset. + * @param offset The offset to start reading from. + * @param ignoreComments If set, comments will be overread. + * @return Returns the token id. + * @exception CoreException Thrown when the end of the file has been reached (code END_OF_FILE) + * or a lexical error was detected while scanning (code LEXICAL_ERROR) + */ + public int readNext(int offset, boolean ignoreComments) throws CoreException { + setOffset(offset); + return readNext(ignoreComments); + } + + /** + * Reads the next token from the given offset and returns the start offset of the token. + * @param offset The offset to start reading from. + * @param ignoreComments If set, comments will be overread + * @return Returns the start position of the next token. + * @exception CoreException Thrown when the end of the file has been reached (code END_OF_FILE) + * or a lexical error was detected while scanning (code LEXICAL_ERROR) + */ + public int getNextStartOffset(int offset, boolean ignoreComments) throws CoreException { + readNext(offset, ignoreComments); + return getCurrentStartOffset(); + } + + /** + * Reads the next token from the given offset and returns the offset after the token. + * @param offset The offset to start reading from. + * @param ignoreComments If set, comments will be overread + * @return Returns the start position of the next token. + * @exception CoreException Thrown when the end of the file has been reached (code END_OF_FILE) + * or a lexical error was detected while scanning (code LEXICAL_ERROR) + */ + public int getNextEndOffset(int offset, boolean ignoreComments) throws CoreException { + readNext(offset, ignoreComments); + return getCurrentEndOffset(); + } + + /** + * Reads until a token is reached. + * @param tok The token to read to. + * @exception CoreException Thrown when the end of the file has been reached (code END_OF_FILE) + * or a lexical error was detected while scanning (code LEXICAL_ERROR) + */ + public void readToToken(int tok) throws CoreException { + int curr= 0; + do { + curr= readNext(false); + } while (curr != tok); + } + + /** + * Reads until a token is reached, starting from the given offset. + * @param tok The token to read to. + * @param offset The offset to start reading from. + * @exception CoreException Thrown when the end of the file has been reached (code END_OF_FILE) + * or a lexical error was detected while scanning (code LEXICAL_ERROR) + */ + public void readToToken(int tok, int offset) throws CoreException { + setOffset(offset); + readToToken(tok); + } + + /** + * Reads from the given offset until a token is reached and returns the start offset of the token. + * @param token The token to be found. + * @param startOffset The offset to start reading from. + * @return Returns the start position of the found token. + * @exception CoreException Thrown when the end of the file has been reached (code END_OF_FILE) + * or a lexical error was detected while scanning (code LEXICAL_ERROR) + */ + public int getTokenStartOffset(int token, int startOffset) throws CoreException { + readToToken(token, startOffset); + return getCurrentStartOffset(); + } + + /** + * Reads from the given offset until a token is reached and returns the offset after the token. + * @param token The token to be found. + * @param startOffset Offset to start reading from + * @return Returns the end position of the found token. + * @exception CoreException Thrown when the end of the file has been reached (code END_OF_FILE) + * or a lexical error was detected while scanning (code LEXICAL_ERROR) + */ + public int getTokenEndOffset(int token, int startOffset) throws CoreException { + readToToken(token, startOffset); + return getCurrentEndOffset(); + } + + /** + * Reads from the given offset until a token is reached and returns the offset after the previous token. + * @param token The token to be found. + * @param startOffset The offset to start scanning from. + * @return Returns the end offset of the token previous to the given token. + * @exception CoreException Thrown when the end of the file has been reached (code END_OF_FILE) + * or a lexical error was detected while scanning (code LEXICAL_ERROR) + */ + public int getPreviousTokenEndOffset(int token, int startOffset) throws CoreException { + setOffset(startOffset); + int res= startOffset; + int curr= readNext(false); + while (curr != token) { + res= getCurrentEndOffset(); + curr= readNext(false); + } + return res; + } + + public static boolean isComment(int token) { + return token == TerminalTokens.TokenNameCOMMENT_BLOCK || token == TerminalTokens.TokenNameCOMMENT_JAVADOC + || token == TerminalTokens.TokenNameCOMMENT_LINE; + } + + public static boolean isModifier(int token) { + switch (token) { + case TerminalTokens.TokenNamepublic: + case TerminalTokens.TokenNameprotected: + case TerminalTokens.TokenNameprivate: + case TerminalTokens.TokenNamestatic: + case TerminalTokens.TokenNamefinal: + case TerminalTokens.TokenNameabstract: + case TerminalTokens.TokenNamenative: + case TerminalTokens.TokenNamevolatile: + case TerminalTokens.TokenNamestrictfp: + case TerminalTokens.TokenNametransient: + case TerminalTokens.TokenNamesynchronized: + return true; + default: + return false; + } + } + + public static IStatus createError(int code, String message, Throwable throwable) { + return new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, code, message, throwable); + } + +} diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/TrackedNodePosition.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/TrackedNodePosition.java new file mode 100644 index 000000000..3c971f4ae --- /dev/null +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/TrackedNodePosition.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2000, 2009 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.core.dom.rewrite; + +import org.eclipse.text.edits.TextEdit; +import org.eclipse.text.edits.TextEditGroup; + +import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.rewrite.ITrackedNodePosition; +import org.eclipse.jface.text.IRegion; + +/** + * + */ +public class TrackedNodePosition implements ITrackedNodePosition { + + private final TextEditGroup group; + private final ASTNode node; + + public TrackedNodePosition(TextEditGroup group, ASTNode node) { + this.group= group; + this.node= node; + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.corext.dom.ITrackedNodePosition#getStartPosition() + */ + public int getStartPosition() { + if (this.group.isEmpty()) { + return this.node.getStartPosition(); + } + IRegion coverage= TextEdit.getCoverage(this.group.getTextEdits()); + if (coverage == null) { + return this.node.getStartPosition(); + } + return coverage.getOffset(); + } + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.corext.dom.ITrackedNodePosition#getLength() + */ + public int getLength() { + if (this.group.isEmpty()) { + return this.node.getLength(); + } + IRegion coverage= TextEdit.getCoverage(this.group.getTextEdits()); + if (coverage == null) { + return this.node.getLength(); + } + return coverage.getLength(); + } +} |