Source Code Cross Referenced for ImportRewrite.java in  » IDE-Eclipse » jdt » org » eclipse » jdt » core » dom » rewrite » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » IDE Eclipse » jdt » org.eclipse.jdt.core.dom.rewrite 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*******************************************************************************
0002:         * Copyright (c) 2000, 2007 IBM Corporation and others.
0003:         * All rights reserved. This program and the accompanying materials
0004:         * are made available under the terms of the Eclipse Public License v1.0
0005:         * which accompanies this distribution, and is available at
0006:         * http://www.eclipse.org/legal/epl-v10.html
0007:         *
0008:         * Contributors:
0009:         *     IBM Corporation - initial API and implementation
0010:         *******************************************************************************/package org.eclipse.jdt.core.dom.rewrite;
0011:
0012:        import java.util.ArrayList;
0013:        import java.util.List;
0014:
0015:        import org.eclipse.core.runtime.CoreException;
0016:        import org.eclipse.core.runtime.IProgressMonitor;
0017:        import org.eclipse.core.runtime.NullProgressMonitor;
0018:        import org.eclipse.core.runtime.SubProgressMonitor;
0019:        import org.eclipse.jdt.core.Flags;
0020:        import org.eclipse.jdt.core.ICompilationUnit;
0021:        import org.eclipse.jdt.core.IImportDeclaration;
0022:        import org.eclipse.jdt.core.ITypeRoot;
0023:        import org.eclipse.jdt.core.JavaModelException;
0024:        import org.eclipse.jdt.core.Signature;
0025:        import org.eclipse.jdt.core.compiler.CharOperation;
0026:        import org.eclipse.jdt.core.dom.*;
0027:        import org.eclipse.jdt.internal.core.dom.rewrite.ImportRewriteAnalyzer;
0028:        import org.eclipse.jdt.internal.core.util.Messages;
0029:        import org.eclipse.text.edits.MultiTextEdit;
0030:        import org.eclipse.text.edits.TextEdit;
0031:
0032:        /**
0033:         * The {@link ImportRewrite} helps updating imports following a import order and on-demand imports threshold as configured by a project.
0034:         * <p>
0035:         * 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
0036:         * {@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.
0037:         * 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.
0038:         * </p>
0039:         * <p>
0040:         * On {@link #rewriteImports(IProgressMonitor)} the rewrite translates these descriptions into
0041:         * text edits that can then be applied to the original source. The rewrite infrastructure tries to generate minimal text changes and only
0042:         * 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}
0043:         * as long as no import statements are modified by the AST rewrite.
0044:         * </p>
0045:         * <p>The options controlling the import order and on-demand thresholds are:
0046:         * <ul><li>{@link #setImportOrder(String[])} specifies the import groups and their preferred order</li>
0047:         * <li>{@link #setOnDemandImportThreshold(int)} specifies the number of imports in a group needed for a on-demand import statement (star import)</li>
0048:         * <li>{@link #setStaticOnDemandImportThreshold(int)} specifies the number of static imports in a group needed for a on-demand import statement (star import)</li>
0049:         *</ul>
0050:         * This class is not intended to be subclassed.
0051:         * </p>
0052:         * @since 3.2
0053:         */
0054:        public final class ImportRewrite {
0055:
0056:            /**
0057:             * A {@link ImportRewrite.ImportRewriteContext} can optionally be used in e.g. {@link ImportRewrite#addImport(String, ImportRewrite.ImportRewriteContext)} to
0058:             * give more information about the types visible in the scope. These types can be for example inherited inner types where it is
0059:             * unnecessary to add import statements for. 
0060:             * 
0061:             * </p>
0062:             * <p>
0063:             * This class can be implemented by clients.
0064:             * </p>
0065:             */
0066:            public static abstract class ImportRewriteContext {
0067:
0068:                /**
0069:                 * Result constant signaling that the given element is know in the context. 
0070:                 */
0071:                public final static int RES_NAME_FOUND = 1;
0072:
0073:                /**
0074:                 * Result constant signaling that the given element is not know in the context. 
0075:                 */
0076:                public final static int RES_NAME_UNKNOWN = 2;
0077:
0078:                /**
0079:                 * Result constant signaling that the given element is conflicting with an other element in the context. 
0080:                 */
0081:                public final static int RES_NAME_CONFLICT = 3;
0082:
0083:                /**
0084:                 * Kind constant specifying that the element is a type import.
0085:                 */
0086:                public final static int KIND_TYPE = 1;
0087:
0088:                /**
0089:                 * Kind constant specifying that the element is a static field import.
0090:                 */
0091:                public final static int KIND_STATIC_FIELD = 2;
0092:
0093:                /**
0094:                 * Kind constant specifying that the element is a static method import.
0095:                 */
0096:                public final static int KIND_STATIC_METHOD = 3;
0097:
0098:                /**
0099:                 * Searches for the given element in the context and reports if the element is known ({@link #RES_NAME_FOUND}),
0100:                 * unknown ({@link #RES_NAME_UNKNOWN}) or if its name conflicts ({@link #RES_NAME_CONFLICT}) with an other element.
0101:                 * @param qualifier The qualifier of the element, can be package or the qualified name of a type 
0102:                 * @param name The simple name of the element; either a type, method or field name or * for on-demand imports.
0103:                 * @param kind The kind of the element. Can be either {@link #KIND_TYPE}, {@link #KIND_STATIC_FIELD} or
0104:                 * {@link #KIND_STATIC_METHOD}. Implementors should be prepared for new, currently unspecified kinds and return
0105:                 * {@link #RES_NAME_UNKNOWN} by default.
0106:                 * @return Returns the result of the lookup. Can be either {@link #RES_NAME_FOUND}, {@link #RES_NAME_UNKNOWN} or
0107:                 * {@link #RES_NAME_CONFLICT}.
0108:                 */
0109:                public abstract int findInContext(String qualifier,
0110:                        String name, int kind);
0111:            }
0112:
0113:            private static final char STATIC_PREFIX = 's';
0114:            private static final char NORMAL_PREFIX = 'n';
0115:
0116:            private final ImportRewriteContext defaultContext;
0117:
0118:            private final ICompilationUnit compilationUnit;
0119:            private final CompilationUnit astRoot;
0120:
0121:            private final boolean restoreExistingImports;
0122:            private final List existingImports;
0123:
0124:            private String[] importOrder;
0125:            private int importOnDemandThreshold;
0126:            private int staticImportOnDemandThreshold;
0127:
0128:            private List addedImports;
0129:            private List removedImports;
0130:
0131:            private String[] createdImports;
0132:            private String[] createdStaticImports;
0133:
0134:            private boolean filterImplicitImports;
0135:
0136:            /**
0137:             * Creates a {@link ImportRewrite} from a {@link ICompilationUnit}. If <code>restoreExistingImports</code>
0138:             * is <code>true</code>, all existing imports are kept, and new imports will be inserted at best matching locations. If
0139:             * <code>restoreExistingImports</code> is <code>false</code>, the existing imports will be removed and only the
0140:             * newly added imports will be created.
0141:             * <p>
0142:             * Note that {@link #create(ICompilationUnit, boolean)} is more efficient than this method if an AST for
0143:             * the compilation unit is already available.
0144:             * </p>
0145:             * @param cu the compilation unit to create the imports for
0146:             * @param restoreExistingImports specifies if the existing imports should be kept or removed.
0147:             * @return the created import rewriter.
0148:             * @throws JavaModelException thrown when the compilation unit could not be accessed.
0149:             */
0150:            public static ImportRewrite create(ICompilationUnit cu,
0151:                    boolean restoreExistingImports) throws JavaModelException {
0152:                if (cu == null) {
0153:                    throw new IllegalArgumentException(
0154:                            "Compilation unit must not be null"); //$NON-NLS-1$
0155:                }
0156:                List existingImport = null;
0157:                if (restoreExistingImports) {
0158:                    existingImport = new ArrayList();
0159:                    IImportDeclaration[] imports = cu.getImports();
0160:                    for (int i = 0; i < imports.length; i++) {
0161:                        IImportDeclaration curr = imports[i];
0162:                        char prefix = Flags.isStatic(curr.getFlags()) ? STATIC_PREFIX
0163:                                : NORMAL_PREFIX;
0164:                        existingImport.add(prefix + curr.getElementName());
0165:                    }
0166:                }
0167:                return new ImportRewrite(cu, null, existingImport);
0168:            }
0169:
0170:            /**
0171:             * Creates a {@link ImportRewrite} from a an AST ({@link CompilationUnit}). The AST has to be created from a
0172:             * {@link ICompilationUnit}, that means {@link ASTParser#setSource(ICompilationUnit)} has been used when creating the
0173:             * AST. If <code>restoreExistingImports</code> is <code>true</code>, all existing imports are kept, and new imports
0174:             * will be inserted at best matching locations. If <code>restoreExistingImports</code> is <code>false</code>, the
0175:             * existing imports will be removed and only the newly added imports will be created.
0176:             * <p>
0177:             * Note that this method is more efficient than using {@link #create(ICompilationUnit, boolean)} if an AST is already available.
0178:             * </p>
0179:             * @param astRoot the AST root node to create the imports for
0180:             * @param restoreExistingImports specifies if the existing imports should be kept or removed.
0181:             * @return the created import rewriter.
0182:             * @throws IllegalArgumentException thrown when the passed AST is null or was not created from a compilation unit.
0183:             */
0184:            public static ImportRewrite create(CompilationUnit astRoot,
0185:                    boolean restoreExistingImports) {
0186:                if (astRoot == null) {
0187:                    throw new IllegalArgumentException("AST must not be null"); //$NON-NLS-1$
0188:                }
0189:                ITypeRoot typeRoot = astRoot.getTypeRoot();
0190:                if (!(typeRoot instanceof  ICompilationUnit)) {
0191:                    throw new IllegalArgumentException(
0192:                            "AST must have been constructed from a Java element"); //$NON-NLS-1$
0193:                }
0194:                List existingImport = null;
0195:                if (restoreExistingImports) {
0196:                    existingImport = new ArrayList();
0197:                    List imports = astRoot.imports();
0198:                    for (int i = 0; i < imports.size(); i++) {
0199:                        ImportDeclaration curr = (ImportDeclaration) imports
0200:                                .get(i);
0201:                        StringBuffer buf = new StringBuffer();
0202:                        buf
0203:                                .append(
0204:                                        curr.isStatic() ? STATIC_PREFIX
0205:                                                : NORMAL_PREFIX).append(
0206:                                        curr.getName().getFullyQualifiedName());
0207:                        if (curr.isOnDemand()) {
0208:                            if (buf.length() > 1)
0209:                                buf.append('.');
0210:                            buf.append('*');
0211:                        }
0212:                        existingImport.add(buf.toString());
0213:                    }
0214:                }
0215:                return new ImportRewrite((ICompilationUnit) typeRoot, astRoot,
0216:                        existingImport);
0217:            }
0218:
0219:            private ImportRewrite(ICompilationUnit cu, CompilationUnit astRoot,
0220:                    List existingImports) {
0221:                this .compilationUnit = cu;
0222:                this .astRoot = astRoot; // might be null
0223:                if (existingImports != null) {
0224:                    this .existingImports = existingImports;
0225:                    this .restoreExistingImports = !existingImports.isEmpty();
0226:                } else {
0227:                    this .existingImports = new ArrayList();
0228:                    this .restoreExistingImports = false;
0229:                }
0230:                this .filterImplicitImports = true;
0231:
0232:                this .defaultContext = new ImportRewriteContext() {
0233:                    public int findInContext(String qualifier, String name,
0234:                            int kind) {
0235:                        return findInImports(qualifier, name, kind);
0236:                    }
0237:                };
0238:                this .addedImports = null; // Initialized on use
0239:                this .removedImports = null; // Initialized on use
0240:                this .createdImports = null;
0241:                this .createdStaticImports = null;
0242:
0243:                this .importOrder = CharOperation.NO_STRINGS;
0244:                this .importOnDemandThreshold = 99;
0245:                this .staticImportOnDemandThreshold = 99;
0246:            }
0247:
0248:            /**
0249:             * Defines the import groups and order to be used by the {@link ImportRewrite}.
0250:             * Imports are added to the group matching their qualified name most. The empty group name groups all imports not matching
0251:             * any other group. Static imports are managed in separate groups. Static import group names are prefixed with a '#' character.
0252:             * @param order A list of strings defining the import groups. A group name must be a valid package name or empty. If can be
0253:             * prefixed by the '#' character for static import groups 
0254:             */
0255:            public void setImportOrder(String[] order) {
0256:                if (order == null)
0257:                    throw new IllegalArgumentException("Order must not be null"); //$NON-NLS-1$
0258:                this .importOrder = order;
0259:            }
0260:
0261:            /**
0262:             *	Sets the on-demand import threshold for normal (non-static) imports.
0263:             *	This threshold defines the number of imports that need to be in a group to use
0264:             * a on-demand (star) import declaration instead.
0265:             * 
0266:             * @param threshold a positive number defining the on-demand import threshold
0267:             * for normal (non-static) imports.
0268:             * @throws IllegalArgumentException a {@link IllegalArgumentException} is thrown
0269:             * if the number is not positive.
0270:             */
0271:            public void setOnDemandImportThreshold(int threshold) {
0272:                if (threshold <= 0)
0273:                    throw new IllegalArgumentException(
0274:                            "Threshold must be positive."); //$NON-NLS-1$
0275:                this .importOnDemandThreshold = threshold;
0276:            }
0277:
0278:            /**
0279:             *	Sets the on-demand import threshold for static imports.
0280:             *	This threshold defines the number of imports that need to be in a group to use
0281:             * a on-demand (star) import declaration instead.
0282:             * 
0283:             * @param threshold a positive number defining the on-demand import threshold
0284:             * for normal (non-static) imports.
0285:             * @throws IllegalArgumentException a {@link IllegalArgumentException} is thrown
0286:             * if the number is not positive.
0287:             */
0288:            public void setStaticOnDemandImportThreshold(int threshold) {
0289:                if (threshold <= 0)
0290:                    throw new IllegalArgumentException(
0291:                            "Threshold must be positive."); //$NON-NLS-1$
0292:                this .staticImportOnDemandThreshold = threshold;
0293:            }
0294:
0295:            /**
0296:             * The compilation unit for which this import rewrite was created for.
0297:             * @return the compilation unit for which this import rewrite was created for.
0298:             */
0299:            public ICompilationUnit getCompilationUnit() {
0300:                return this .compilationUnit;
0301:            }
0302:
0303:            /**
0304:             * Returns the default rewrite context that only knows about the imported types. Clients
0305:             * can write their own context and use the default context for the default behavior.
0306:             * @return the default import rewrite context.
0307:             */
0308:            public ImportRewriteContext getDefaultImportRewriteContext() {
0309:                return this .defaultContext;
0310:            }
0311:
0312:            /**
0313:             * Specifies that implicit imports (types in default package, package <code>java.lang</code> or
0314:             * in the same package as the rewrite compilation unit should not be created except if necessary
0315:             * to resolve an on-demand import conflict. The filter is enabled by default.
0316:             * @param filterImplicitImports if set, implicit imports will be filtered.
0317:             */
0318:            public void setFilterImplicitImports(boolean filterImplicitImports) {
0319:                this .filterImplicitImports = filterImplicitImports;
0320:            }
0321:
0322:            private static int compareImport(char prefix, String qualifier,
0323:                    String name, String curr) {
0324:                if (curr.charAt(0) != prefix || !curr.endsWith(name)) {
0325:                    return ImportRewriteContext.RES_NAME_UNKNOWN;
0326:                }
0327:
0328:                curr = curr.substring(1); // remove the prefix
0329:
0330:                if (curr.length() == name.length()) {
0331:                    if (qualifier.length() == 0) {
0332:                        return ImportRewriteContext.RES_NAME_FOUND;
0333:                    }
0334:                    return ImportRewriteContext.RES_NAME_CONFLICT;
0335:                }
0336:                // at this place: curr.length > name.length
0337:
0338:                int dotPos = curr.length() - name.length() - 1;
0339:                if (curr.charAt(dotPos) != '.') {
0340:                    return ImportRewriteContext.RES_NAME_UNKNOWN;
0341:                }
0342:                if (qualifier.length() != dotPos || !curr.startsWith(qualifier)) {
0343:                    return ImportRewriteContext.RES_NAME_CONFLICT;
0344:                }
0345:                return ImportRewriteContext.RES_NAME_FOUND;
0346:            }
0347:
0348:            /**
0349:             * Not API, package visibility as accessed from an anonymous type
0350:             */
0351:            /* package */final int findInImports(String qualifier,
0352:                    String name, int kind) {
0353:                boolean allowAmbiguity = (kind == ImportRewriteContext.KIND_STATIC_METHOD)
0354:                        || (name.length() == 1 && name.charAt(0) == '*');
0355:                List imports = this .existingImports;
0356:                char prefix = (kind == ImportRewriteContext.KIND_TYPE) ? NORMAL_PREFIX
0357:                        : STATIC_PREFIX;
0358:
0359:                for (int i = imports.size() - 1; i >= 0; i--) {
0360:                    String curr = (String) imports.get(i);
0361:                    int res = compareImport(prefix, qualifier, name, curr);
0362:                    if (res != ImportRewriteContext.RES_NAME_UNKNOWN) {
0363:                        if (!allowAmbiguity
0364:                                || res == ImportRewriteContext.RES_NAME_FOUND) {
0365:                            return res;
0366:                        }
0367:                    }
0368:                }
0369:                return ImportRewriteContext.RES_NAME_UNKNOWN;
0370:            }
0371:
0372:            /**
0373:             * Adds a new import to the rewriter's record and returns a {@link Type} node that can be used
0374:             * in the code as a reference to the type. The type binding can be an array binding, type variable or wildcard.
0375:             * If the binding is a generic type, the type parameters are ignored. For parameterized types, also the type
0376:             * arguments are processed and imports added if necessary. Anonymous types inside type arguments are normalized to their base type, wildcard
0377:             * of wildcards are ignored.
0378:             * 	<p>
0379:             * 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.
0380:             * </p>
0381:             * <p>
0382:             * The content of the compilation unit itself is actually not modified
0383:             * in any way by this method; rather, the rewriter just records that a new import has been added.
0384:             * </p>
0385:             * @param typeSig the signature of the type to be added.
0386:             * @param ast the AST to create the returned type for.
0387:             * @return returns a type to which the type binding can be assigned to. The returned type contains is unqualified
0388:             * when an import could be added or was already known. It is fully qualified, if an import conflict prevented the import.
0389:             */
0390:            public Type addImportFromSignature(String typeSig, AST ast) {
0391:                return addImportFromSignature(typeSig, ast, this .defaultContext);
0392:            }
0393:
0394:            /**
0395:             * Adds a new import to the rewriter's record and returns a {@link Type} node that can be used
0396:             * in the code as a reference to the type. The type binding can be an array binding, type variable or wildcard.
0397:             * If the binding is a generic type, the type parameters are ignored. For parameterized types, also the type
0398:             * arguments are processed and imports added if necessary. Anonymous types inside type arguments are normalized to their base type, wildcard
0399:             * of wildcards are ignored.
0400:             * 	<p>
0401:             * 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.
0402:             * </p>
0403:             * <p>
0404:             * The content of the compilation unit itself is actually not modified
0405:             * in any way by this method; rather, the rewriter just records that a new import has been added.
0406:             * </p>
0407:             * @param typeSig the signature of the type to be added.
0408:             * @param ast the AST to create the returned type for.
0409:             * @param context an optional context that knows about types visible in the current scope or <code>null</code>
0410:             * to use the default context only using the available imports.
0411:             * @return returns a type to which the type binding can be assigned to. The returned type contains is unqualified
0412:             * when an import could be added or was already known. It is fully qualified, if an import conflict prevented the import.
0413:             */
0414:            public Type addImportFromSignature(String typeSig, AST ast,
0415:                    ImportRewriteContext context) {
0416:                if (typeSig == null || typeSig.length() == 0) {
0417:                    throw new IllegalArgumentException(
0418:                            "Invalid type signature: empty or null"); //$NON-NLS-1$
0419:                }
0420:                int sigKind = Signature.getTypeSignatureKind(typeSig);
0421:                switch (sigKind) {
0422:                case Signature.BASE_TYPE_SIGNATURE:
0423:                    return ast.newPrimitiveType(PrimitiveType.toCode(Signature
0424:                            .toString(typeSig)));
0425:                case Signature.ARRAY_TYPE_SIGNATURE:
0426:                    Type elementType = addImportFromSignature(Signature
0427:                            .getElementType(typeSig), ast, context);
0428:                    return ast.newArrayType(elementType, Signature
0429:                            .getArrayCount(typeSig));
0430:                case Signature.CLASS_TYPE_SIGNATURE:
0431:                    String erasureSig = Signature.getTypeErasure(typeSig);
0432:
0433:                    String erasureName = Signature.toString(erasureSig);
0434:                    if (erasureSig.charAt(0) == Signature.C_RESOLVED) {
0435:                        erasureName = internalAddImport(erasureName, context);
0436:                    }
0437:                    Type baseType = ast.newSimpleType(ast.newName(erasureName));
0438:                    String[] typeArguments = Signature
0439:                            .getTypeArguments(typeSig);
0440:                    if (typeArguments.length > 0) {
0441:                        ParameterizedType type = ast
0442:                                .newParameterizedType(baseType);
0443:                        List argNodes = type.typeArguments();
0444:                        for (int i = 0; i < typeArguments.length; i++) {
0445:                            String curr = typeArguments[i];
0446:                            if (containsNestedCapture(curr)) { // see bug 103044
0447:                                argNodes.add(ast.newWildcardType());
0448:                            } else {
0449:                                argNodes.add(addImportFromSignature(curr, ast,
0450:                                        context));
0451:                            }
0452:                        }
0453:                        return type;
0454:                    }
0455:                    return baseType;
0456:                case Signature.TYPE_VARIABLE_SIGNATURE:
0457:                    return ast.newSimpleType(ast.newSimpleName(Signature
0458:                            .toString(typeSig)));
0459:                case Signature.WILDCARD_TYPE_SIGNATURE:
0460:                    WildcardType wildcardType = ast.newWildcardType();
0461:                    char ch = typeSig.charAt(0);
0462:                    if (ch != Signature.C_STAR) {
0463:                        Type bound = addImportFromSignature(typeSig
0464:                                .substring(1), ast, context);
0465:                        wildcardType.setBound(bound, ch == Signature.C_EXTENDS);
0466:                    }
0467:                    return wildcardType;
0468:                case Signature.CAPTURE_TYPE_SIGNATURE:
0469:                    return addImportFromSignature(typeSig.substring(1), ast,
0470:                            context);
0471:                default:
0472:                    throw new IllegalArgumentException(
0473:                            "Unknown type signature kind: " + typeSig); //$NON-NLS-1$
0474:                }
0475:            }
0476:
0477:            /**
0478:             * Adds a new import to the rewriter's record and returns a type reference that can be used
0479:             * in the code. The type binding can be an array binding, type variable or wildcard.
0480:             * If the binding is a generic type, the type parameters are ignored. For parameterized types, also the type
0481:             * arguments are processed and imports added if necessary. Anonymous types inside type arguments are normalized to their base type, wildcard
0482:             * of wildcards are ignored. 
0483:             * 	<p>
0484:             * 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.
0485:             * </p>
0486:             * <p>
0487:             * The content of the compilation unit itself is actually not modified
0488:             * in any way by this method; rather, the rewriter just records that a new import has been added.
0489:             * </p>
0490:             * @param binding the signature of the type to be added.
0491:             * @return returns a type to which the type binding can be assigned to. The returned type contains is unqualified
0492:             * when an import could be added or was already known. It is fully qualified, if an import conflict prevented the import.
0493:             */
0494:            public String addImport(ITypeBinding binding) {
0495:                return addImport(binding, this .defaultContext);
0496:            }
0497:
0498:            /**
0499:             * Adds a new import to the rewriter's record and returns a type reference that can be used
0500:             * in the code. The type binding can be an array binding, type variable or wildcard.
0501:             * If the binding is a generic type, the type parameters are ignored. For parameterized types, also the type
0502:             * arguments are processed and imports added if necessary. Anonymous types inside type arguments are normalized to their base type, wildcard
0503:             * of wildcards are ignored.
0504:             * 	<p>
0505:             * 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.
0506:             * </p>
0507:             * <p>
0508:             * The content of the compilation unit itself is actually not modified
0509:             * in any way by this method; rather, the rewriter just records that a new import has been added.
0510:             * </p>
0511:             * @param binding the signature of the type to be added.
0512:             * @param context an optional context that knows about types visible in the current scope or <code>null</code>
0513:             * to use the default context only using the available imports.
0514:             * @return returns a type to which the type binding can be assigned to. The returned type contains is unqualified
0515:             * when an import could be added or was already known. It is fully qualified, if an import conflict prevented the import.
0516:             */
0517:            public String addImport(ITypeBinding binding,
0518:                    ImportRewriteContext context) {
0519:                if (binding.isPrimitive() || binding.isTypeVariable()
0520:                        || binding.isRecovered()) {
0521:                    return binding.getName();
0522:                }
0523:
0524:                ITypeBinding normalizedBinding = normalizeTypeBinding(binding);
0525:                if (normalizedBinding == null) {
0526:                    return "invalid"; //$NON-NLS-1$
0527:                }
0528:                if (normalizedBinding.isWildcardType()) {
0529:                    StringBuffer res = new StringBuffer("?"); //$NON-NLS-1$
0530:                    ITypeBinding bound = normalizedBinding.getBound();
0531:                    if (bound != null && !bound.isWildcardType()
0532:                            && !bound.isCapture()) { // bug 95942
0533:                        if (normalizedBinding.isUpperbound()) {
0534:                            res.append(" extends "); //$NON-NLS-1$
0535:                        } else {
0536:                            res.append(" super "); //$NON-NLS-1$
0537:                        }
0538:                        res.append(addImport(bound, context));
0539:                    }
0540:                    return res.toString();
0541:                }
0542:
0543:                if (normalizedBinding.isArray()) {
0544:                    StringBuffer res = new StringBuffer(addImport(
0545:                            normalizedBinding.getElementType(), context));
0546:                    for (int i = normalizedBinding.getDimensions(); i > 0; i--) {
0547:                        res.append("[]"); //$NON-NLS-1$
0548:                    }
0549:                    return res.toString();
0550:                }
0551:
0552:                String qualifiedName = getRawQualifiedName(normalizedBinding);
0553:                if (qualifiedName.length() > 0) {
0554:                    String str = internalAddImport(qualifiedName, context);
0555:
0556:                    ITypeBinding[] typeArguments = normalizedBinding
0557:                            .getTypeArguments();
0558:                    if (typeArguments.length > 0) {
0559:                        StringBuffer res = new StringBuffer(str);
0560:                        res.append('<');
0561:                        for (int i = 0; i < typeArguments.length; i++) {
0562:                            if (i > 0) {
0563:                                res.append(',');
0564:                            }
0565:                            ITypeBinding curr = typeArguments[i];
0566:                            if (containsNestedCapture(curr, false)) { // see bug 103044
0567:                                res.append('?');
0568:                            } else {
0569:                                res.append(addImport(curr, context));
0570:                            }
0571:                        }
0572:                        res.append('>');
0573:                        return res.toString();
0574:                    }
0575:                    return str;
0576:                }
0577:                return getRawName(normalizedBinding);
0578:            }
0579:
0580:            private boolean containsNestedCapture(ITypeBinding binding,
0581:                    boolean isNested) {
0582:                if (binding == null || binding.isPrimitive()
0583:                        || binding.isTypeVariable()) {
0584:                    return false;
0585:                }
0586:                if (binding.isCapture()) {
0587:                    if (isNested) {
0588:                        return true;
0589:                    }
0590:                    return containsNestedCapture(binding.getWildcard(), true);
0591:                }
0592:                if (binding.isWildcardType()) {
0593:                    return containsNestedCapture(binding.getBound(), true);
0594:                }
0595:                if (binding.isArray()) {
0596:                    return containsNestedCapture(binding.getElementType(), true);
0597:                }
0598:                ITypeBinding[] typeArguments = binding.getTypeArguments();
0599:                for (int i = 0; i < typeArguments.length; i++) {
0600:                    if (containsNestedCapture(typeArguments[i], true)) {
0601:                        return true;
0602:                    }
0603:                }
0604:                return false;
0605:            }
0606:
0607:            private boolean containsNestedCapture(String signature) {
0608:                return signature.length() > 1
0609:                        && signature.indexOf(Signature.C_CAPTURE, 1) != -1;
0610:            }
0611:
0612:            private static ITypeBinding normalizeTypeBinding(
0613:                    ITypeBinding binding) {
0614:                if (binding != null && !binding.isNullType()
0615:                        && !"void".equals(binding.getName())) { //$NON-NLS-1$
0616:                    if (binding.isAnonymous()) {
0617:                        ITypeBinding[] baseBindings = binding.getInterfaces();
0618:                        if (baseBindings.length > 0) {
0619:                            return baseBindings[0];
0620:                        }
0621:                        return binding.getSuperclass();
0622:                    }
0623:                    if (binding.isCapture()) {
0624:                        return binding.getWildcard();
0625:                    }
0626:                    return binding;
0627:                }
0628:                return null;
0629:            }
0630:
0631:            /**
0632:             * Adds a new import to the rewriter's record and returns a {@link Type} that can be used
0633:             * in the code. The type binding can be an array binding, type variable or wildcard.
0634:             * If the binding is a generic type, the type parameters are ignored. For parameterized types, also the type
0635:             * arguments are processed and imports added if necessary. Anonymous types inside type arguments are normalized to their base type, wildcard
0636:             * of wildcards are ignored.
0637:             * 	<p>
0638:             * 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.
0639:             * </p>
0640:             * <p>
0641:             * The content of the compilation unit itself is actually not modified
0642:             * in any way by this method; rather, the rewriter just records that a new import has been added.
0643:             * </p>
0644:             * @param binding the signature of the type to be added.
0645:             * @param ast the AST to create the returned type for.
0646:             * @return returns a type to which the type binding can be assigned to. The returned type contains is unqualified
0647:             * when an import could be added or was already known. It is fully qualified, if an import conflict prevented the import.
0648:             */
0649:            public Type addImport(ITypeBinding binding, AST ast) {
0650:                return addImport(binding, ast, this .defaultContext);
0651:            }
0652:
0653:            /**
0654:             * Adds a new import to the rewriter's record and returns a {@link Type} that can be used
0655:             * in the code. The type binding can be an array binding, type variable or wildcard.
0656:             * If the binding is a generic type, the type parameters are ignored. For parameterized types, also the type
0657:             * arguments are processed and imports added if necessary. Anonymous types inside type arguments are normalized to their base type, wildcard
0658:             * of wildcards are ignored. 
0659:             * 	<p>
0660:             * 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.
0661:             * </p>
0662:             * <p>
0663:             * The content of the compilation unit itself is actually not modified
0664:             * in any way by this method; rather, the rewriter just records that a new import has been added.
0665:             * </p>
0666:             * @param binding the signature of the type to be added.
0667:             * @param ast the AST to create the returned type for.
0668:             * @param context an optional context that knows about types visible in the current scope or <code>null</code>
0669:             * to use the default context only using the available imports.
0670:             * @return returns a type to which the type binding can be assigned to. The returned type contains is unqualified
0671:             * when an import could be added or was already known. It is fully qualified, if an import conflict prevented the import.
0672:             */
0673:            public Type addImport(ITypeBinding binding, AST ast,
0674:                    ImportRewriteContext context) {
0675:                if (binding.isPrimitive()) {
0676:                    return ast.newPrimitiveType(PrimitiveType.toCode(binding
0677:                            .getName()));
0678:                }
0679:
0680:                ITypeBinding normalizedBinding = normalizeTypeBinding(binding);
0681:                if (normalizedBinding == null) {
0682:                    return ast.newSimpleType(ast.newSimpleName("invalid")); //$NON-NLS-1$
0683:                }
0684:
0685:                if (normalizedBinding.isTypeVariable()) {
0686:                    // no import
0687:                    return ast.newSimpleType(ast.newSimpleName(binding
0688:                            .getName()));
0689:                }
0690:                if (normalizedBinding.isWildcardType()) {
0691:                    WildcardType wcType = ast.newWildcardType();
0692:                    ITypeBinding bound = normalizedBinding.getBound();
0693:                    if (bound != null && !bound.isWildcardType()
0694:                            && !bound.isCapture()) { // bug 96942
0695:                        Type boundType = addImport(bound, ast, context);
0696:                        wcType.setBound(boundType, normalizedBinding
0697:                                .isUpperbound());
0698:                    }
0699:                    return wcType;
0700:                }
0701:
0702:                if (normalizedBinding.isArray()) {
0703:                    Type elementType = addImport(normalizedBinding
0704:                            .getElementType(), ast, context);
0705:                    return ast.newArrayType(elementType, normalizedBinding
0706:                            .getDimensions());
0707:                }
0708:
0709:                String qualifiedName = getRawQualifiedName(normalizedBinding);
0710:                if (qualifiedName.length() > 0) {
0711:                    String res = internalAddImport(qualifiedName, context);
0712:
0713:                    ITypeBinding[] typeArguments = normalizedBinding
0714:                            .getTypeArguments();
0715:                    if (typeArguments.length > 0) {
0716:                        Type erasureType = ast.newSimpleType(ast.newName(res));
0717:                        ParameterizedType paramType = ast
0718:                                .newParameterizedType(erasureType);
0719:                        List arguments = paramType.typeArguments();
0720:                        for (int i = 0; i < typeArguments.length; i++) {
0721:                            ITypeBinding curr = typeArguments[i];
0722:                            if (containsNestedCapture(curr, false)) { // see bug 103044
0723:                                arguments.add(ast.newWildcardType());
0724:                            } else {
0725:                                arguments.add(addImport(curr, ast, context));
0726:                            }
0727:                        }
0728:                        return paramType;
0729:                    }
0730:                    return ast.newSimpleType(ast.newName(res));
0731:                }
0732:                return ast.newSimpleType(ast
0733:                        .newName(getRawName(normalizedBinding)));
0734:            }
0735:
0736:            /**
0737:             * Adds a new import to the rewriter's record and returns a type reference that can be used
0738:             * in the code. The type binding can only be an array or non-generic type.
0739:             * 	<p>
0740:             * 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.
0741:             * </p>
0742:             * <p>
0743:             * The content of the compilation unit itself is actually not modified
0744:             * in any way by this method; rather, the rewriter just records that a new import has been added.
0745:             * </p>
0746:             * @param qualifiedTypeName the qualified type name of the type to be added
0747:             * @param context an optional context that knows about types visible in the current scope or <code>null</code>
0748:             * to use the default context only using the available imports.
0749:             * @return returns a type to which the type binding can be assigned to. The returned type contains is unqualified
0750:             * when an import could be added or was already known. It is fully qualified, if an import conflict prevented the import.
0751:             */
0752:            public String addImport(String qualifiedTypeName,
0753:                    ImportRewriteContext context) {
0754:                int angleBracketOffset = qualifiedTypeName.indexOf('<');
0755:                if (angleBracketOffset != -1) {
0756:                    return internalAddImport(qualifiedTypeName.substring(0,
0757:                            angleBracketOffset), context)
0758:                            + qualifiedTypeName.substring(angleBracketOffset);
0759:                }
0760:                int bracketOffset = qualifiedTypeName.indexOf('[');
0761:                if (bracketOffset != -1) {
0762:                    return internalAddImport(qualifiedTypeName.substring(0,
0763:                            bracketOffset), context)
0764:                            + qualifiedTypeName.substring(bracketOffset);
0765:                }
0766:                return internalAddImport(qualifiedTypeName, context);
0767:            }
0768:
0769:            /**
0770:             * Adds a new import to the rewriter's record and returns a type reference that can be used
0771:             * in the code. The type binding can only be an array or non-generic type.
0772:             * 	<p>
0773:             * 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.
0774:             * </p>
0775:             * <p>
0776:             * The content of the compilation unit itself is actually not modified
0777:             * in any way by this method; rather, the rewriter just records that a new import has been added.
0778:             * </p>
0779:             * @param qualifiedTypeName the qualified type name of the type to be added
0780:             * @return returns a type to which the type binding can be assigned to. The returned type contains is unqualified
0781:             * when an import could be added or was already known. It is fully qualified, if an import conflict prevented the import.
0782:             */
0783:            public String addImport(String qualifiedTypeName) {
0784:                return addImport(qualifiedTypeName, this .defaultContext);
0785:            }
0786:
0787:            /**
0788:             * Adds a new static import to the rewriter's record and returns a reference that can be used in the code. The reference will
0789:             * be fully qualified if an import conflict prevented the import or unqualified if the import succeeded or was already
0790:             * existing.
0791:             * 	<p>
0792:             * 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.
0793:             * </p>
0794:             * <p>
0795:             * The content of the compilation unit itself is actually not modified
0796:             * in any way by this method; rather, the rewriter just records that a new import has been added.
0797:             * </p>
0798:             * @param binding The binding of the static field or method to be added.
0799:             * @return returns either the simple member name if the import was successful or else the qualified name if
0800:             * an import conflict prevented the import.
0801:             * @throws IllegalArgumentException an {@link IllegalArgumentException} is thrown if the binding is not a static field
0802:             * or method.
0803:             */
0804:            public String addStaticImport(IBinding binding) {
0805:                return addStaticImport(binding, this .defaultContext);
0806:            }
0807:
0808:            /**
0809:             * Adds a new static import to the rewriter's record and returns a reference that can be used in the code. The reference will
0810:             * be fully qualified if an import conflict prevented the import or unqualified if the import succeeded or was already
0811:             * existing.
0812:             * 	<p>
0813:             * 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.
0814:             * </p>
0815:             * <p>
0816:             * The content of the compilation unit itself is actually not modified
0817:             * in any way by this method; rather, the rewriter just records that a new import has been added.
0818:             * </p>
0819:             * @param binding The binding of the static field or method to be added.
0820:             * @param context an optional context that knows about members visible in the current scope or <code>null</code>
0821:             * to use the default context only using the available imports.
0822:             * @return returns either the simple member name if the import was successful or else the qualified name if
0823:             * an import conflict prevented the import.
0824:             * @throws IllegalArgumentException an {@link IllegalArgumentException} is thrown if the binding is not a static field
0825:             * or method.
0826:             */
0827:            public String addStaticImport(IBinding binding,
0828:                    ImportRewriteContext context) {
0829:                if (Modifier.isStatic(binding.getModifiers())) {
0830:                    if (binding instanceof  IVariableBinding) {
0831:                        IVariableBinding variableBinding = (IVariableBinding) binding;
0832:                        if (variableBinding.isField()) {
0833:                            ITypeBinding declaringType = variableBinding
0834:                                    .getDeclaringClass();
0835:                            return addStaticImport(
0836:                                    getRawQualifiedName(declaringType), binding
0837:                                            .getName(), true, context);
0838:                        }
0839:                    } else if (binding instanceof  IMethodBinding) {
0840:                        ITypeBinding declaringType = ((IMethodBinding) binding)
0841:                                .getDeclaringClass();
0842:                        return addStaticImport(
0843:                                getRawQualifiedName(declaringType), binding
0844:                                        .getName(), false, context);
0845:                    }
0846:                }
0847:                throw new IllegalArgumentException(
0848:                        "Binding must be a static field or method."); //$NON-NLS-1$
0849:            }
0850:
0851:            /**
0852:             * Adds a new static import to the rewriter's record and returns a reference that can be used in the code. The reference will
0853:             * be fully qualified if an import conflict prevented the import or unqualified if the import succeeded or was already
0854:             * existing.
0855:             * 	<p>
0856:             * 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.
0857:             * </p>
0858:             * <p>
0859:             * The content of the compilation unit itself is actually not modified
0860:             * in any way by this method; rather, the rewriter just records that a new import has been added.
0861:             * </p>
0862:             * @param declaringTypeName The qualified name of the static's member declaring type
0863:             * @param simpleName the simple name of the member; either a field or a method name.
0864:             * @param isField <code>true</code> specifies that the member is a field, <code>false</code> if it is a
0865:             * method.
0866:             * @return returns either the simple member name if the import was successful or else the qualified name if
0867:             * an import conflict prevented the import.
0868:             */
0869:            public String addStaticImport(String declaringTypeName,
0870:                    String simpleName, boolean isField) {
0871:                return addStaticImport(declaringTypeName, simpleName, isField,
0872:                        this .defaultContext);
0873:            }
0874:
0875:            /**
0876:             * Adds a new static import to the rewriter's record and returns a reference that can be used in the code. The reference will
0877:             * be fully qualified if an import conflict prevented the import or unqualified if the import succeeded or was already
0878:             * existing.
0879:             * 	<p>
0880:             * 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.
0881:             * </p>
0882:             * <p>
0883:             * The content of the compilation unit itself is actually not modified
0884:             * in any way by this method; rather, the rewriter just records that a new import has been added.
0885:             * </p>
0886:             * @param declaringTypeName The qualified name of the static's member declaring type
0887:             * @param simpleName the simple name of the member; either a field or a method name.
0888:             * @param isField <code>true</code> specifies that the member is a field, <code>false</code> if it is a
0889:             * method.
0890:             * @param context an optional context that knows about members visible in the current scope or <code>null</code>
0891:             * to use the default context only using the available imports.
0892:             * @return returns either the simple member name if the import was successful or else the qualified name if
0893:             * an import conflict prevented the import.
0894:             */
0895:            public String addStaticImport(String declaringTypeName,
0896:                    String simpleName, boolean isField,
0897:                    ImportRewriteContext context) {
0898:                if (declaringTypeName.indexOf('.') == -1) {
0899:                    return declaringTypeName + '.' + simpleName;
0900:                }
0901:                if (context == null) {
0902:                    context = this .defaultContext;
0903:                }
0904:                int kind = isField ? ImportRewriteContext.KIND_STATIC_FIELD
0905:                        : ImportRewriteContext.KIND_STATIC_METHOD;
0906:                int res = context.findInContext(declaringTypeName, simpleName,
0907:                        kind);
0908:                if (res == ImportRewriteContext.RES_NAME_CONFLICT) {
0909:                    return declaringTypeName + '.' + simpleName;
0910:                }
0911:                if (res == ImportRewriteContext.RES_NAME_UNKNOWN) {
0912:                    addEntry(STATIC_PREFIX + declaringTypeName + '.'
0913:                            + simpleName);
0914:                }
0915:                return simpleName;
0916:            }
0917:
0918:            private String internalAddImport(String fullTypeName,
0919:                    ImportRewriteContext context) {
0920:                int idx = fullTypeName.lastIndexOf('.');
0921:                String typeContainerName, typeName;
0922:                if (idx != -1) {
0923:                    typeContainerName = fullTypeName.substring(0, idx);
0924:                    typeName = fullTypeName.substring(idx + 1);
0925:                } else {
0926:                    typeContainerName = ""; //$NON-NLS-1$
0927:                    typeName = fullTypeName;
0928:                }
0929:
0930:                if (typeContainerName.length() == 0
0931:                        && PrimitiveType.toCode(typeName) != null) {
0932:                    return fullTypeName;
0933:                }
0934:
0935:                if (context == null)
0936:                    context = this .defaultContext;
0937:
0938:                int res = context.findInContext(typeContainerName, typeName,
0939:                        ImportRewriteContext.KIND_TYPE);
0940:                if (res == ImportRewriteContext.RES_NAME_CONFLICT) {
0941:                    return fullTypeName;
0942:                }
0943:                if (res == ImportRewriteContext.RES_NAME_UNKNOWN) {
0944:                    addEntry(NORMAL_PREFIX + fullTypeName);
0945:                }
0946:                return typeName;
0947:            }
0948:
0949:            private void addEntry(String entry) {
0950:                this .existingImports.add(entry);
0951:
0952:                if (this .removedImports != null) {
0953:                    if (this .removedImports.remove(entry)) {
0954:                        return;
0955:                    }
0956:                }
0957:
0958:                if (this .addedImports == null) {
0959:                    this .addedImports = new ArrayList();
0960:                }
0961:                this .addedImports.add(entry);
0962:            }
0963:
0964:            private boolean removeEntry(String entry) {
0965:                if (this .existingImports.remove(entry)) {
0966:                    if (this .addedImports != null) {
0967:                        if (this .addedImports.remove(entry)) {
0968:                            return true;
0969:                        }
0970:                    }
0971:                    if (this .removedImports == null) {
0972:                        this .removedImports = new ArrayList();
0973:                    }
0974:                    this .removedImports.add(entry);
0975:                    return true;
0976:                }
0977:                return false;
0978:            }
0979:
0980:            /**
0981:             * Records to remove a import. No remove is recorded if no such import exists or if such an import is recorded
0982:             * to be added. In that case the record of the addition is discarded.
0983:             * <p>
0984:             * The content of the compilation unit itself is actually not modified
0985:             * in any way by this method; rather, the rewriter just records that an import has been removed.
0986:             * </p>
0987:             * @param qualifiedName The import name to remove.
0988:             * @return <code>true</code> is returned of an import of the given name could be found.
0989:             */
0990:            public boolean removeImport(String qualifiedName) {
0991:                return removeEntry(NORMAL_PREFIX + qualifiedName);
0992:            }
0993:
0994:            /**
0995:             * Records to remove a static import. No remove is recorded if no such import exists or if such an import is recorded
0996:             * to be added. In that case the record of the addition is discarded.
0997:             * <p>
0998:             * The content of the compilation unit itself is actually not modified
0999:             * in any way by this method; rather, the rewriter just records that a new import has been removed.
1000:             * </p>
1001:             * @param qualifiedName The import name to remove.
1002:             * @return <code>true</code> is returned of an import of the given name could be found.
1003:             */
1004:            public boolean removeStaticImport(String qualifiedName) {
1005:                return removeEntry(STATIC_PREFIX + qualifiedName);
1006:            }
1007:
1008:            private static String getRawName(ITypeBinding normalizedBinding) {
1009:                return normalizedBinding.getTypeDeclaration().getName();
1010:            }
1011:
1012:            private static String getRawQualifiedName(
1013:                    ITypeBinding normalizedBinding) {
1014:                return normalizedBinding.getTypeDeclaration()
1015:                        .getQualifiedName();
1016:            }
1017:
1018:            /**
1019:             * Converts all modifications recorded by this rewriter into an object representing the corresponding text
1020:             * edits to the source code of the rewrite's compilation unit. The compilation unit itself is not modified.
1021:             * <p>
1022:             * Calling this methods does not discard the modifications on record. Subsequence modifications are added
1023:             * to the ones already on record. If this method is called again later, the resulting text edit object will accurately
1024:             * reflect the net cumulative affect of all those changes.
1025:             * </p>
1026:             * @param monitor the progress monitor or <code>null</code>
1027:             * @return text edit object describing the changes to the document corresponding to the changes
1028:             * recorded by this rewriter
1029:             * @throws CoreException the exception is thrown if the rewrite fails.
1030:             */
1031:            public final TextEdit rewriteImports(IProgressMonitor monitor)
1032:                    throws CoreException {
1033:                if (monitor == null) {
1034:                    monitor = new NullProgressMonitor();
1035:                }
1036:
1037:                try {
1038:                    monitor
1039:                            .beginTask(
1040:                                    Messages
1041:                                            .bind(Messages.importRewrite_processDescription),
1042:                                    2);
1043:                    if (!hasRecordedChanges()) {
1044:                        this .createdImports = CharOperation.NO_STRINGS;
1045:                        this .createdStaticImports = CharOperation.NO_STRINGS;
1046:                        return new MultiTextEdit();
1047:                    }
1048:
1049:                    CompilationUnit usedAstRoot = this .astRoot;
1050:                    if (usedAstRoot == null) {
1051:                        ASTParser parser = ASTParser.newParser(AST.JLS3);
1052:                        parser.setSource(this .compilationUnit);
1053:                        parser.setFocalPosition(0); // reduced AST
1054:                        parser.setResolveBindings(false);
1055:                        usedAstRoot = (CompilationUnit) parser
1056:                                .createAST(new SubProgressMonitor(monitor, 1));
1057:                    }
1058:
1059:                    ImportRewriteAnalyzer computer = new ImportRewriteAnalyzer(
1060:                            this .compilationUnit, usedAstRoot,
1061:                            this .importOrder, this .importOnDemandThreshold,
1062:                            this .staticImportOnDemandThreshold,
1063:                            this .restoreExistingImports);
1064:                    computer
1065:                            .setFilterImplicitImports(this .filterImplicitImports);
1066:
1067:                    if (this .addedImports != null) {
1068:                        for (int i = 0; i < this .addedImports.size(); i++) {
1069:                            String curr = (String) this .addedImports.get(i);
1070:                            computer.addImport(curr.substring(1),
1071:                                    STATIC_PREFIX == curr.charAt(0));
1072:                        }
1073:                    }
1074:
1075:                    if (this .removedImports != null) {
1076:                        for (int i = 0; i < this .removedImports.size(); i++) {
1077:                            String curr = (String) this .removedImports.get(i);
1078:                            computer.removeImport(curr.substring(1),
1079:                                    STATIC_PREFIX == curr.charAt(0));
1080:                        }
1081:                    }
1082:
1083:                    TextEdit result = computer
1084:                            .getResultingEdits(new SubProgressMonitor(monitor,
1085:                                    1));
1086:                    this .createdImports = computer.getCreatedImports();
1087:                    this .createdStaticImports = computer
1088:                            .getCreatedStaticImports();
1089:                    return result;
1090:                } finally {
1091:                    monitor.done();
1092:                }
1093:            }
1094:
1095:            /**
1096:             * Returns all new non-static imports created by the last invocation of {@link #rewriteImports(IProgressMonitor)}
1097:             * or <code>null</code> if these methods have not been called yet.
1098:             * <p>
1099:             * 	Note that this list doesn't need to be the same as the added imports (see {@link #getAddedImports()}) as
1100:             * implicit imports are not created and some imports are represented by on-demand imports instead.
1101:             * </p>
1102:             * @return the created imports
1103:             */
1104:            public String[] getCreatedImports() {
1105:                return this .createdImports;
1106:            }
1107:
1108:            /**
1109:             * Returns all new static imports created by the last invocation of {@link #rewriteImports(IProgressMonitor)}
1110:             * or <code>null</code> if these methods have not been called yet.
1111:             * <p>
1112:             * Note that this list doesn't need to be the same as the added static imports ({@link #getAddedStaticImports()}) as
1113:             * implicit imports are not created and some imports are represented by on-demand imports instead.
1114:             * </p
1115:             * @return the created imports
1116:             */
1117:            public String[] getCreatedStaticImports() {
1118:                return this .createdStaticImports;
1119:            }
1120:
1121:            /**
1122:             * Returns all non-static imports that are recorded to be added.
1123:             * 
1124:             * @return the imports recorded to be added.
1125:             */
1126:            public String[] getAddedImports() {
1127:                return filterFromList(this .addedImports, NORMAL_PREFIX);
1128:            }
1129:
1130:            /**
1131:             * Returns all static imports that are recorded to be added.
1132:             * 
1133:             * @return the static imports recorded to be added.
1134:             */
1135:            public String[] getAddedStaticImports() {
1136:                return filterFromList(this .addedImports, STATIC_PREFIX);
1137:            }
1138:
1139:            /**
1140:             * Returns all non-static imports that are recorded to be removed.
1141:             * 
1142:             * @return the imports recorded to be removed.
1143:             */
1144:            public String[] getRemovedImports() {
1145:                return filterFromList(this .removedImports, NORMAL_PREFIX);
1146:            }
1147:
1148:            /**
1149:             * Returns all static imports that are recorded to be removed.
1150:             * 
1151:             * @return the static imports recorded to be removed.
1152:             */
1153:            public String[] getRemovedStaticImports() {
1154:                return filterFromList(this .removedImports, STATIC_PREFIX);
1155:            }
1156:
1157:            /**
1158:             * Returns <code>true</code> if imports have been recorded to be added or removed.
1159:             * @return boolean returns if any changes to imports have been recorded.
1160:             */
1161:            public boolean hasRecordedChanges() {
1162:                return !this .restoreExistingImports
1163:                        || (this .addedImports != null && !this .addedImports
1164:                                .isEmpty())
1165:                        || (this .removedImports != null && !this .removedImports
1166:                                .isEmpty());
1167:            }
1168:
1169:            private static String[] filterFromList(List imports, char prefix) {
1170:                if (imports == null) {
1171:                    return CharOperation.NO_STRINGS;
1172:                }
1173:                ArrayList res = new ArrayList();
1174:                for (int i = 0; i < imports.size(); i++) {
1175:                    String curr = (String) imports.get(i);
1176:                    if (prefix == curr.charAt(0)) {
1177:                        res.add(curr.substring(1));
1178:                    }
1179:                }
1180:                return (String[]) res.toArray(new String[res.size()]);
1181:            }
1182:
1183:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.