Source Code Cross Referenced for IntroduceHint.java in  » IDE-Netbeans » java » org » netbeans » modules » java » hints » introduce » 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 Netbeans » java » org.netbeans.modules.java.hints.introduce 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003:         *
0004:         * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005:         *
0006:         * The contents of this file are subject to the terms of either the GNU
0007:         * General Public License Version 2 only ("GPL") or the Common
0008:         * Development and Distribution License("CDDL") (collectively, the
0009:         * "License"). You may not use this file except in compliance with the
0010:         * License. You can obtain a copy of the License at
0011:         * http://www.netbeans.org/cddl-gplv2.html
0012:         * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013:         * specific language governing permissions and limitations under the
0014:         * License.  When distributing the software, include this License Header
0015:         * Notice in each file and include the License file at
0016:         * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
0017:         * particular file as subject to the "Classpath" exception as provided
0018:         * by Sun in the GPL Version 2 section of the License file that
0019:         * accompanied this code. If applicable, add the following below the
0020:         * License Header, with the fields enclosed by brackets [] replaced by
0021:         * your own identifying information:
0022:         * "Portions Copyrighted [year] [name of copyright owner]"
0023:         *
0024:         * Contributor(s):
0025:         *
0026:         * The Original Software is NetBeans. The Initial Developer of the Original
0027:         * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
0028:         * Microsystems, Inc. All Rights Reserved.
0029:         *
0030:         * If you wish your version of this file to be governed by only the CDDL
0031:         * or only the GPL Version 2, indicate your decision by adding
0032:         * "[Contributor] elects to include this software in this distribution
0033:         * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034:         * single choice of license, a recipient has the option to distribute
0035:         * your version of this file under either the CDDL, the GPL Version 2 or
0036:         * to extend the choice of license to its licensees as provided above.
0037:         * However, if you add GPL Version 2 code and therefore, elected the GPL
0038:         * Version 2 license, then the option applies only if the new code is
0039:         * made subject to such option by the copyright holder.
0040:         */
0041:        package org.netbeans.modules.java.hints.introduce;
0042:
0043:        import com.sun.source.tree.AssignmentTree;
0044:        import com.sun.source.tree.BinaryTree;
0045:        import com.sun.source.tree.BlockTree;
0046:        import com.sun.source.tree.BreakTree;
0047:        import com.sun.source.tree.ClassTree;
0048:        import com.sun.source.tree.CompoundAssignmentTree;
0049:        import com.sun.source.tree.ContinueTree;
0050:        import com.sun.source.tree.DoWhileLoopTree;
0051:        import com.sun.source.tree.ExpressionTree;
0052:        import com.sun.source.tree.ForLoopTree;
0053:        import com.sun.source.tree.IdentifierTree;
0054:        import com.sun.source.tree.IfTree;
0055:        import com.sun.source.tree.MethodTree;
0056:        import com.sun.source.tree.ModifiersTree;
0057:        import com.sun.source.tree.NewClassTree;
0058:        import com.sun.source.tree.ReturnTree;
0059:        import com.sun.source.tree.Scope;
0060:        import com.sun.source.tree.StatementTree;
0061:        import com.sun.source.tree.Tree;
0062:        import com.sun.source.tree.Tree.Kind;
0063:        import com.sun.source.tree.TypeParameterTree;
0064:        import com.sun.source.tree.UnaryTree;
0065:        import com.sun.source.tree.VariableTree;
0066:        import com.sun.source.tree.WhileLoopTree;
0067:        import com.sun.source.util.SourcePositions;
0068:        import com.sun.source.util.TreePath;
0069:        import com.sun.source.util.TreePathScanner;
0070:        import java.io.IOException;
0071:        import java.util.Arrays;
0072:        import java.util.Collections;
0073:        import java.util.EnumMap;
0074:        import java.util.EnumSet;
0075:        import java.util.HashSet;
0076:        import java.util.Iterator;
0077:        import java.util.LinkedHashSet;
0078:        import java.util.LinkedList;
0079:        import java.util.List;
0080:        import java.util.Map;
0081:        import java.util.Set;
0082:        import java.util.concurrent.atomic.AtomicBoolean;
0083:        import javax.lang.model.element.Element;
0084:        import javax.lang.model.element.ElementKind;
0085:        import javax.lang.model.element.ExecutableElement;
0086:        import javax.lang.model.element.Modifier;
0087:        import javax.lang.model.element.TypeElement;
0088:        import javax.lang.model.element.VariableElement;
0089:        import javax.lang.model.type.DeclaredType;
0090:        import javax.lang.model.type.TypeKind;
0091:        import javax.lang.model.type.TypeMirror;
0092:        import javax.swing.JButton;
0093:        import javax.swing.text.BadLocationException;
0094:        import javax.swing.text.Document;
0095:        import org.netbeans.api.java.lexer.JavaTokenId;
0096:        import org.netbeans.api.java.source.CancellableTask;
0097:        import org.netbeans.api.java.source.Task;
0098:        import org.netbeans.api.java.source.CompilationInfo;
0099:        import org.netbeans.api.java.source.JavaSource;
0100:        import org.netbeans.api.java.source.JavaSource.Phase;
0101:        import org.netbeans.api.java.source.TreeMaker;
0102:        import org.netbeans.api.java.source.TreePathHandle;
0103:        import org.netbeans.api.java.source.TypeMirrorHandle;
0104:        import org.netbeans.api.java.source.WorkingCopy;
0105:        import org.netbeans.api.java.source.support.CaretAwareJavaSourceTaskFactory;
0106:        import org.netbeans.api.java.source.support.SelectionAwareJavaSourceTaskFactory;
0107:        import org.netbeans.api.lexer.TokenSequence;
0108:        import org.netbeans.modules.java.editor.codegen.GeneratorUtils;
0109:        import org.netbeans.modules.java.hints.errors.Utilities;
0110:        import org.netbeans.spi.editor.hints.ChangeInfo;
0111:        import org.netbeans.spi.editor.hints.ErrorDescription;
0112:        import org.netbeans.spi.editor.hints.ErrorDescriptionFactory;
0113:        import org.netbeans.spi.editor.hints.Fix;
0114:        import org.netbeans.spi.editor.hints.HintsController;
0115:        import org.netbeans.spi.editor.hints.Severity;
0116:        import org.openide.DialogDescriptor;
0117:        import org.openide.DialogDisplayer;
0118:        import org.openide.filesystems.FileObject;
0119:        import org.openide.util.NbBundle;
0120:
0121:        /**
0122:         *
0123:         * @author Jan Lahoda
0124:         */
0125:        public class IntroduceHint implements  CancellableTask<CompilationInfo> {
0126:
0127:            private AtomicBoolean cancel = new AtomicBoolean();
0128:
0129:            public IntroduceHint() {
0130:            }
0131:
0132:            private static final Set<TypeKind> NOT_ACCEPTED_TYPES = EnumSet.of(
0133:                    TypeKind.ERROR, TypeKind.NONE, TypeKind.OTHER,
0134:                    TypeKind.VOID, TypeKind.EXECUTABLE);
0135:            private static final Set<JavaTokenId> WHITESPACES = EnumSet.of(
0136:                    JavaTokenId.WHITESPACE, JavaTokenId.BLOCK_COMMENT,
0137:                    JavaTokenId.LINE_COMMENT, JavaTokenId.JAVADOC_COMMENT);
0138:
0139:            static int[] ignoreWhitespaces(CompilationInfo ci, int start,
0140:                    int end) {
0141:                TokenSequence<JavaTokenId> ts = ci.getTokenHierarchy()
0142:                        .tokenSequence(JavaTokenId.language());
0143:
0144:                if (ts == null) {
0145:                    return new int[] { start, end };
0146:                }
0147:
0148:                ts.move(start);
0149:
0150:                if (ts.moveNext()) {
0151:                    boolean wasMoveNext = true;
0152:
0153:                    while (WHITESPACES.contains(ts.token().id())
0154:                            && (wasMoveNext = ts.moveNext()))
0155:                        ;
0156:
0157:                    if (wasMoveNext && ts.offset() > start)
0158:                        start = ts.offset();
0159:                }
0160:
0161:                ts.move(end);
0162:
0163:                while (ts.movePrevious()
0164:                        && WHITESPACES.contains(ts.token().id())
0165:                        && ts.offset() < end)
0166:                    end = ts.offset();
0167:
0168:                return new int[] { start, end };
0169:            }
0170:
0171:            static TreePath validateSelection(CompilationInfo ci, int start,
0172:                    int end) {
0173:                TreePath tp = ci.getTreeUtilities().pathFor(
0174:                        (start + end) / 2 + 1);
0175:
0176:                for (; tp != null; tp = tp.getParentPath()) {
0177:                    Tree leaf = tp.getLeaf();
0178:
0179:                    if (StatementTree.class.isAssignableFrom(leaf.getKind()
0180:                            .asInterface()))
0181:                        return null;
0182:
0183:                    if (!ExpressionTree.class.isAssignableFrom(leaf.getKind()
0184:                            .asInterface()))
0185:                        continue;
0186:
0187:                    long treeStart = ci.getTrees().getSourcePositions()
0188:                            .getStartPosition(ci.getCompilationUnit(), leaf);
0189:                    long treeEnd = ci.getTrees().getSourcePositions()
0190:                            .getEndPosition(ci.getCompilationUnit(), leaf);
0191:
0192:                    if (treeStart != start || treeEnd != end) {
0193:                        continue;
0194:                    }
0195:
0196:                    TypeMirror type = ci.getTrees().getTypeMirror(tp);
0197:
0198:                    if (type == null
0199:                            || NOT_ACCEPTED_TYPES.contains(type.getKind()))
0200:                        continue;
0201:
0202:                    if (tp.getParentPath().getLeaf().getKind() == Kind.EXPRESSION_STATEMENT)
0203:                        continue;
0204:
0205:                    if (tp.getLeaf().getKind() == Kind.ANNOTATION)
0206:                        continue;
0207:
0208:                    if (!isInsideClass(tp))
0209:                        return null;
0210:
0211:                    TreePath candidate = tp;
0212:
0213:                    tp = tp.getParentPath();
0214:
0215:                    while (tp != null) {
0216:                        switch (tp.getLeaf().getKind()) {
0217:                        case VARIABLE:
0218:                            VariableTree vt = (VariableTree) tp.getLeaf();
0219:                            if (vt.getInitializer() == leaf) {
0220:                                return candidate;
0221:                            } else {
0222:                                return null;
0223:                            }
0224:                        case NEW_CLASS:
0225:                            NewClassTree nct = (NewClassTree) tp.getLeaf();
0226:
0227:                            for (Tree p : nct.getArguments()) {
0228:                                if (p == leaf) {
0229:                                    return candidate;
0230:                                }
0231:                            }
0232:
0233:                            return null;
0234:                        }
0235:
0236:                        leaf = tp.getLeaf();
0237:                        tp = tp.getParentPath();
0238:                    }
0239:
0240:                    return candidate;
0241:                }
0242:
0243:                return null;
0244:            }
0245:
0246:            static TreePathHandle validateSelectionForIntroduceMethod(
0247:                    CompilationInfo ci, int start, int end, int[] statementsSpan) {
0248:                int[] span = ignoreWhitespaces(ci, Math.min(start, end), Math
0249:                        .max(start, end));
0250:
0251:                start = span[0];
0252:                end = span[1];
0253:
0254:                if (start >= end)
0255:                    return null;
0256:
0257:                TreePath tpStart = ci.getTreeUtilities().pathFor(start);
0258:                TreePath tpEnd = ci.getTreeUtilities().pathFor(end);
0259:
0260:                if (tpStart.getLeaf() != tpEnd.getLeaf()
0261:                        || tpStart.getLeaf().getKind() != Kind.BLOCK) {
0262:                    //??? not in the same block:
0263:                    return null;
0264:                }
0265:
0266:                int from = -1;
0267:                int to = -1;
0268:
0269:                BlockTree block = (BlockTree) tpStart.getLeaf();
0270:                int index = 0;
0271:
0272:                for (StatementTree s : block.getStatements()) {
0273:                    long sStart = ci.getTrees().getSourcePositions()
0274:                            .getStartPosition(ci.getCompilationUnit(), s);
0275:
0276:                    if (sStart == start) {
0277:                        from = index;
0278:                    }
0279:
0280:                    if (end < sStart && to == (-1)) {
0281:                        to = index - 1;
0282:                    }
0283:
0284:                    index++;
0285:                }
0286:
0287:                if (from == (-1)) {
0288:                    return null;
0289:                }
0290:
0291:                if (to == (-1))
0292:                    to = block.getStatements().size() - 1;
0293:
0294:                if (to < from) {
0295:                    return null;
0296:                }
0297:
0298:                statementsSpan[0] = from;
0299:                statementsSpan[1] = to;
0300:
0301:                return TreePathHandle.create(tpStart, ci);
0302:            }
0303:
0304:            public void run(CompilationInfo info) {
0305:                cancel.set(false);
0306:
0307:                FileObject file = info.getFileObject();
0308:                int[] selection = SelectionAwareJavaSourceTaskFactory
0309:                        .getLastSelection(file);
0310:
0311:                if (selection == null) {
0312:                    //nothing to do....
0313:                    HintsController.setErrors(info.getFileObject(),
0314:                            IntroduceHint.class.getName(), Collections
0315:                                    .<ErrorDescription> emptyList());
0316:                } else {
0317:                    HintsController.setErrors(info.getFileObject(),
0318:                            IntroduceHint.class.getName(), computeError(info,
0319:                                    selection[0], selection[1], null,
0320:                                    new EnumMap<IntroduceKind, String>(
0321:                                            IntroduceKind.class), cancel));
0322:                }
0323:            }
0324:
0325:            public void cancel() {
0326:                cancel.set(true);
0327:            }
0328:
0329:            private static boolean isConstructor(CompilationInfo info,
0330:                    TreePath path) {
0331:                Element e = info.getTrees().getElement(path);
0332:
0333:                return e != null && e.getKind() == ElementKind.CONSTRUCTOR;
0334:            }
0335:
0336:            private static List<TreePath> findConstructors(
0337:                    CompilationInfo info, TreePath method) {
0338:                List<TreePath> result = new LinkedList<TreePath>();
0339:                TreePath parent = method.getParentPath();
0340:
0341:                if (parent.getLeaf().getKind() == Kind.CLASS) {
0342:                    for (Tree t : ((ClassTree) parent.getLeaf()).getMembers()) {
0343:                        TreePath tp = new TreePath(parent, t);
0344:
0345:                        if (isConstructor(info, tp)) {
0346:                            result.add(tp);
0347:                        }
0348:                    }
0349:                }
0350:
0351:                return result;
0352:            }
0353:
0354:            private static boolean isInsideClass(TreePath tp) {
0355:                while (tp != null) {
0356:                    if (tp.getLeaf().getKind() == Kind.CLASS)
0357:                        return true;
0358:
0359:                    tp = tp.getParentPath();
0360:                }
0361:
0362:                return false;
0363:            }
0364:
0365:            static List<ErrorDescription> computeError(CompilationInfo info,
0366:                    int start, int end, Map<IntroduceKind, Fix> fixesMap,
0367:                    Map<IntroduceKind, String> errorMessage,
0368:                    AtomicBoolean cancel) {
0369:                List<ErrorDescription> hints = new LinkedList<ErrorDescription>();
0370:                List<Fix> fixes = new LinkedList<Fix>();
0371:                TreePath resolved = validateSelection(info, start, end);
0372:
0373:                if (resolved != null) {
0374:                    TreePathHandle h = TreePathHandle.create(resolved, info);
0375:                    TreePath method = findMethod(resolved);
0376:                    boolean isConstant = checkConstantExpression(info, resolved);
0377:                    boolean isVariable = findStatement(resolved) != null
0378:                            && method != null;
0379:                    List<TreePath> duplicatesForVariable = isVariable ? CopyFinder
0380:                            .computeDuplicates(info, resolved, method, cancel)
0381:                            : null;
0382:                    List<TreePath> duplicatesForConstant = /*isConstant ? */CopyFinder
0383:                            .computeDuplicates(info, resolved, new TreePath(
0384:                                    info.getCompilationUnit()), cancel);// : null;
0385:                    Scope scope = info.getTrees().getScope(resolved);
0386:                    boolean statik = scope != null ? info.getTreeUtilities()
0387:                            .isStaticContext(scope) : false;
0388:                    String guessedName = Utilities.guessName(info, resolved);
0389:                    Fix variable = isVariable ? new IntroduceFix(h, info
0390:                            .getJavaSource(), guessedName,
0391:                            duplicatesForVariable.size() + 1,
0392:                            IntroduceKind.CREATE_VARIABLE) : null;
0393:                    Fix constant = isConstant ? new IntroduceFix(h, info
0394:                            .getJavaSource(), guessedName,
0395:                            duplicatesForConstant.size() + 1,
0396:                            IntroduceKind.CREATE_CONSTANT) : null;
0397:                    Fix field = null;
0398:                    Fix methodFix = null;
0399:
0400:                    if (method != null) {
0401:                        int[] initilizeIn = computeInitializeIn(info, resolved,
0402:                                duplicatesForConstant);
0403:
0404:                        if (statik) {
0405:                            initilizeIn[0] &= ~IntroduceFieldPanel.INIT_CONSTRUCTORS;
0406:                            initilizeIn[1] &= ~IntroduceFieldPanel.INIT_CONSTRUCTORS;
0407:                        }
0408:
0409:                        boolean allowFinalInCurrentMethod = false;
0410:
0411:                        if (isConstructor(info, method)) {
0412:                            //how many constructors do we have in the target class?:
0413:                            allowFinalInCurrentMethod = findConstructors(info,
0414:                                    method).size() == 1;
0415:                        }
0416:
0417:                        field = new IntroduceFieldFix(h, info.getJavaSource(),
0418:                                guessedName, duplicatesForConstant.size() + 1,
0419:                                initilizeIn, statik, allowFinalInCurrentMethod);
0420:
0421:                        //introduce method based on expression:
0422:                        Element methodEl = info.getTrees().getElement(method);
0423:                        ScanStatement scanner = new ScanStatement(info,
0424:                                resolved.getLeaf(), resolved.getLeaf(), cancel);
0425:
0426:                        if (methodEl != null
0427:                                && (methodEl.getKind() == ElementKind.METHOD || methodEl
0428:                                        .getKind() == ElementKind.CONSTRUCTOR)) {
0429:                            ExecutableElement ee = (ExecutableElement) methodEl;
0430:
0431:                            scanner.localVariables.addAll(ee.getParameters());
0432:                        }
0433:
0434:                        scanner.scan(method, null);
0435:
0436:                        List<TypeMirrorHandle> paramTypes = new LinkedList<TypeMirrorHandle>();
0437:                        List<String> paramNames = new LinkedList<String>();
0438:
0439:                        for (VariableElement ve : scanner.usedLocalVariables) {
0440:                            paramTypes
0441:                                    .add(TypeMirrorHandle.create(ve.asType()));
0442:                            if (ve.getModifiers().contains(Modifier.FINAL)) {
0443:                                paramNames.add("!"
0444:                                        + ve.getSimpleName().toString());
0445:                            } else {
0446:                                paramNames.add(ve.getSimpleName().toString());
0447:                            }
0448:                        }
0449:
0450:                        Set<TypeMirror> exceptions = new HashSet<TypeMirror>(
0451:                                info.getTreeUtilities().getUncaughtExceptions(
0452:                                        resolved));
0453:
0454:                        Set<TypeMirrorHandle> exceptionHandles = new HashSet<TypeMirrorHandle>();
0455:
0456:                        for (TypeMirror tm : exceptions) {
0457:                            exceptionHandles.add(TypeMirrorHandle.create(tm));
0458:                        }
0459:
0460:                        methodFix = new IntroduceExpressionBasedMethodFix(info
0461:                                .getJavaSource(), h, paramTypes, paramNames,
0462:                                exceptionHandles);
0463:                    }
0464:
0465:                    if (fixesMap != null) {
0466:                        fixesMap.put(IntroduceKind.CREATE_VARIABLE, variable);
0467:                        fixesMap.put(IntroduceKind.CREATE_CONSTANT, constant);
0468:                        fixesMap.put(IntroduceKind.CREATE_FIELD, field);
0469:                        fixesMap.put(IntroduceKind.CREATE_METHOD, methodFix);
0470:                    }
0471:
0472:                    if (variable != null) {
0473:                        fixes.add(variable);
0474:                    }
0475:
0476:                    if (constant != null) {
0477:                        fixes.add(constant);
0478:                    }
0479:
0480:                    if (field != null) {
0481:                        fixes.add(field);
0482:                    }
0483:
0484:                    if (methodFix != null) {
0485:                        fixes.add(methodFix);
0486:                    }
0487:                }
0488:
0489:                Fix introduceMethod = computeIntroduceMethod(info, start, end,
0490:                        fixesMap, errorMessage, cancel);
0491:
0492:                if (introduceMethod != null) {
0493:                    fixes.add(introduceMethod);
0494:                    if (fixesMap != null) {
0495:                        fixesMap.put(IntroduceKind.CREATE_METHOD,
0496:                                introduceMethod);
0497:                    }
0498:                }
0499:
0500:                if (!fixes.isEmpty()) {
0501:                    int pos = CaretAwareJavaSourceTaskFactory
0502:                            .getLastPosition(info.getFileObject());
0503:                    String displayName = NbBundle.getMessage(
0504:                            IntroduceHint.class, "HINT_Introduce");
0505:
0506:                    hints.add(ErrorDescriptionFactory.createErrorDescription(
0507:                            Severity.HINT, displayName, fixes, info
0508:                                    .getFileObject(), pos, pos));
0509:                }
0510:
0511:                return hints;
0512:            }
0513:
0514:            static Fix computeIntroduceMethod(CompilationInfo info, int start,
0515:                    int end, Map<IntroduceKind, Fix> fixesMap,
0516:                    Map<IntroduceKind, String> errorMessage,
0517:                    AtomicBoolean cancel) {
0518:                int[] statements = new int[2];
0519:
0520:                TreePathHandle h = validateSelectionForIntroduceMethod(info,
0521:                        start, end, statements);
0522:
0523:                if (h == null) {
0524:                    errorMessage.put(IntroduceKind.CREATE_METHOD,
0525:                            "ERR_Invalid_Selection"); // NOI18N
0526:                    return null;
0527:                }
0528:
0529:                TreePath block = h.resolve(info);
0530:                TreePath method = findMethod(block);
0531:                Element methodEl = info.getTrees().getElement(method);
0532:                BlockTree bt = (BlockTree) block.getLeaf();
0533:                List<? extends StatementTree> statementsToWrap = bt
0534:                        .getStatements().subList(statements[0],
0535:                                statements[1] + 1);
0536:                ScanStatement scanner = new ScanStatement(info,
0537:                        statementsToWrap.get(0), statementsToWrap
0538:                                .get(statementsToWrap.size() - 1), cancel);
0539:                Set<TypeMirror> exceptions = new HashSet<TypeMirror>();
0540:                int index = 0;
0541:                TypeMirror methodReturnType = info.getTypes().getNoType(
0542:                        TypeKind.VOID);
0543:
0544:                if (methodEl != null
0545:                        && (methodEl.getKind() == ElementKind.METHOD || methodEl
0546:                                .getKind() == ElementKind.CONSTRUCTOR)) {
0547:                    ExecutableElement ee = (ExecutableElement) methodEl;
0548:
0549:                    scanner.localVariables.addAll(ee.getParameters());
0550:                    methodReturnType = ee.getReturnType();
0551:                }
0552:
0553:                scanner.scan(method, null);
0554:
0555:                for (StatementTree s : bt.getStatements()) {
0556:                    TreePath path = new TreePath(block, s);
0557:
0558:                    if (index >= statements[0] && index <= statements[1]) {
0559:                        exceptions.addAll(info.getTreeUtilities()
0560:                                .getUncaughtExceptions(path));
0561:                    }
0562:
0563:                    index++;
0564:                }
0565:
0566:                ExitsFromAllBranches efab = new ExitsFromAllBranches(info);
0567:
0568:                boolean exitsFromAllBranches = efab.scan(new TreePath(block,
0569:                        statementsToWrap.get(statementsToWrap.size() - 1)),
0570:                        null) == Boolean.TRUE;
0571:
0572:                String exitsError = scanner.verifyExits(exitsFromAllBranches);
0573:
0574:                if (exitsError != null) {
0575:                    errorMessage.put(IntroduceKind.CREATE_METHOD, exitsError);
0576:                    return null;
0577:                }
0578:
0579:                List<TypeMirrorHandle> paramTypes = new LinkedList<TypeMirrorHandle>();
0580:                List<String> paramNames = new LinkedList<String>();
0581:
0582:                for (VariableElement ve : scanner.usedLocalVariables) {
0583:                    paramTypes.add(TypeMirrorHandle.create(ve.asType()));
0584:                    if (ve.getModifiers().contains(Modifier.FINAL))
0585:                        paramNames.add("!" + ve.getSimpleName().toString());
0586:                    else
0587:                        paramNames.add(ve.getSimpleName().toString());
0588:                }
0589:
0590:                List<VariableElement> additionalLocalVariables = new LinkedList<VariableElement>(
0591:                        scanner.selectionWrittenLocalVariables);
0592:
0593:                additionalLocalVariables.removeAll(scanner.usedLocalVariables);
0594:                additionalLocalVariables
0595:                        .removeAll(scanner.selectionLocalVariables);
0596:
0597:                List<TypeMirrorHandle> additionaLocalTypes = new LinkedList<TypeMirrorHandle>();
0598:                List<String> additionaLocalNames = new LinkedList<String>();
0599:
0600:                for (VariableElement ve : additionalLocalVariables) {
0601:                    additionaLocalTypes.add(TypeMirrorHandle
0602:                            .create(ve.asType()));
0603:                    additionaLocalNames.add(ve.getSimpleName().toString());
0604:                }
0605:
0606:                List<TreePathHandle> exits = new LinkedList<TreePathHandle>();
0607:
0608:                for (TreePath tp : scanner.selectionExits) {
0609:                    exits.add(TreePathHandle.create(tp, info));
0610:                }
0611:
0612:                TypeMirror returnType;
0613:                String returnName;
0614:                boolean declareVariableForReturnValue;
0615:
0616:                if (!scanner.usedSelectionLocalVariables.isEmpty()) {
0617:                    VariableElement result = scanner.usedSelectionLocalVariables
0618:                            .iterator().next();
0619:
0620:                    returnType = result.asType();
0621:                    returnName = result.getSimpleName().toString();
0622:                    declareVariableForReturnValue = scanner.selectionLocalVariables
0623:                            .contains(result);
0624:                } else {
0625:                    if (!exits.isEmpty() && !exitsFromAllBranches) {
0626:                        returnType = info.getTypes().getPrimitiveType(
0627:                                TypeKind.BOOLEAN);
0628:                        returnName = null;
0629:                        declareVariableForReturnValue = false;
0630:                    } else {
0631:                        if (exitsFromAllBranches && scanner.hasReturns) {
0632:                            returnType = methodReturnType;
0633:                            returnName = null;
0634:                            declareVariableForReturnValue = false;
0635:                        } else {
0636:                            returnType = info.getTypes().getNoType(
0637:                                    TypeKind.VOID);
0638:                            returnName = null;
0639:                            declareVariableForReturnValue = false;
0640:                        }
0641:                    }
0642:                }
0643:
0644:                Set<TypeMirrorHandle> exceptionHandles = new HashSet<TypeMirrorHandle>();
0645:
0646:                for (TypeMirror tm : exceptions) {
0647:                    exceptionHandles.add(TypeMirrorHandle.create(tm));
0648:                }
0649:
0650:                return new IntroduceMethodFix(info.getJavaSource(), h,
0651:                        paramTypes, paramNames, additionaLocalTypes,
0652:                        additionaLocalNames, TypeMirrorHandle
0653:                                .create(returnType), returnName,
0654:                        declareVariableForReturnValue, exceptionHandles, exits,
0655:                        exitsFromAllBranches, statements[0], statements[1]);
0656:            }
0657:
0658:            static boolean checkConstantExpression(CompilationInfo info,
0659:                    TreePath path) {
0660:                Tree expr = path.getLeaf();
0661:
0662:                if (expr.getKind().asInterface() == BinaryTree.class) {
0663:                    BinaryTree bt = (BinaryTree) expr;
0664:
0665:                    return checkConstantExpression(info, new TreePath(path, bt
0666:                            .getLeftOperand()))
0667:                            && checkConstantExpression(info, new TreePath(path,
0668:                                    bt.getRightOperand()));
0669:                }
0670:
0671:                if (expr.getKind() == Kind.IDENTIFIER
0672:                        || expr.getKind() == Kind.MEMBER_SELECT) {
0673:                    Element e = info.getTrees().getElement(path);
0674:
0675:                    if (e == null)
0676:                        return false;
0677:
0678:                    if (e.getKind() != ElementKind.FIELD)
0679:                        return false;
0680:
0681:                    if (!e.getModifiers().contains(Modifier.STATIC))
0682:                        return false;
0683:
0684:                    if (!e.getModifiers().contains(Modifier.FINAL))
0685:                        return false;
0686:
0687:                    TypeMirror type = e.asType();
0688:
0689:                    if (type.getKind().isPrimitive())
0690:                        return true;
0691:
0692:                    if (type.getKind() == TypeKind.DECLARED) {
0693:                        TypeElement te = (TypeElement) ((DeclaredType) type)
0694:                                .asElement();
0695:
0696:                        return "java.lang.String".equals(te.getQualifiedName()
0697:                                .toString()); // NOI18N
0698:                    }
0699:
0700:                    return false;
0701:                }
0702:
0703:                return LITERALS.contains(expr.getKind());
0704:            }
0705:
0706:            private static final Set<Kind> LITERALS = EnumSet.of(
0707:                    Kind.STRING_LITERAL, Kind.CHAR_LITERAL, Kind.INT_LITERAL,
0708:                    Kind.LONG_LITERAL, Kind.FLOAT_LITERAL, Kind.DOUBLE_LITERAL);
0709:            private static final Set<ElementKind> LOCAL_VARIABLES = EnumSet.of(
0710:                    ElementKind.EXCEPTION_PARAMETER,
0711:                    ElementKind.LOCAL_VARIABLE, ElementKind.PARAMETER);
0712:
0713:            private static TreePath findStatement(TreePath statementPath) {
0714:                while (statementPath != null
0715:                        && (!StatementTree.class.isAssignableFrom(statementPath
0716:                                .getLeaf().getKind().asInterface()) || (statementPath
0717:                                .getParentPath() != null && statementPath
0718:                                .getParentPath().getLeaf().getKind() != Kind.BLOCK))) {
0719:                    if (statementPath.getLeaf().getKind() == Kind.CLASS)
0720:                        return null;
0721:
0722:                    statementPath = statementPath.getParentPath();
0723:                }
0724:
0725:                return statementPath;
0726:            }
0727:
0728:            private static TreePath findMethod(TreePath path) {
0729:                while (path != null) {
0730:                    if (path.getLeaf().getKind() == Kind.METHOD) {
0731:                        return path;
0732:                    }
0733:
0734:                    if (path.getLeaf().getKind() == Kind.BLOCK
0735:                            && path.getParentPath() != null
0736:                            && path.getParentPath().getLeaf().getKind() == Kind.CLASS) {
0737:                        //initializer:
0738:                        return path;
0739:                    }
0740:
0741:                    path = path.getParentPath();
0742:                }
0743:
0744:                return null;
0745:            }
0746:
0747:            private static TreePath findClass(TreePath path) {
0748:                while (path != null) {
0749:                    if (path.getLeaf().getKind() == Kind.CLASS) {
0750:                        return path;
0751:                    }
0752:
0753:                    path = path.getParentPath();
0754:                }
0755:
0756:                return null;
0757:            }
0758:
0759:            private static boolean isParentOf(TreePath parent, TreePath path) {
0760:                Tree parentLeaf = parent.getLeaf();
0761:
0762:                while (path != null && path.getLeaf() != parentLeaf) {
0763:                    path = path.getParentPath();
0764:                }
0765:
0766:                return path != null;
0767:            }
0768:
0769:            private static boolean isParentOf(TreePath parent,
0770:                    List<? extends TreePath> candidates) {
0771:                for (TreePath tp : candidates) {
0772:                    if (!isParentOf(parent, tp))
0773:                        return false;
0774:                }
0775:
0776:                return true;
0777:            }
0778:
0779:            private static BlockTree findAddPosition(CompilationInfo info,
0780:                    TreePath original, List<? extends TreePath> candidates,
0781:                    int[] outPosition) {
0782:                //find least common block holding all the candidates:
0783:                TreePath statement = original;
0784:
0785:                for (TreePath p : candidates) {
0786:                    Tree leaf = p.getLeaf();
0787:                    int leafStart = (int) info.getTrees().getSourcePositions()
0788:                            .getStartPosition(info.getCompilationUnit(), leaf);
0789:                    int stPathStart = (int) info.getTrees()
0790:                            .getSourcePositions().getStartPosition(
0791:                                    info.getCompilationUnit(),
0792:                                    statement.getLeaf());
0793:
0794:                    if (leafStart < stPathStart) {
0795:                        statement = p;
0796:                    }
0797:                }
0798:
0799:                List<TreePath> allCandidates = new LinkedList<TreePath>();
0800:
0801:                allCandidates.add(original);
0802:                allCandidates.addAll(candidates);
0803:
0804:                statement = findStatement(statement);
0805:
0806:                if (statement == null) {
0807:                    //XXX: well....
0808:                    return null;
0809:                }
0810:
0811:                while (statement.getParentPath() != null
0812:                        && !isParentOf(statement.getParentPath(), allCandidates)) {
0813:                    statement = statement.getParentPath();
0814:                }
0815:
0816:                //#126269: the common parent may not be block:
0817:                while (statement.getParentPath() != null
0818:                        && statement.getParentPath().getLeaf().getKind() != Kind.BLOCK) {
0819:                    statement = statement.getParentPath();
0820:                }
0821:
0822:                if (statement.getParentPath() == null)
0823:                    return null;//XXX: log
0824:
0825:                BlockTree statements = (BlockTree) statement.getParentPath()
0826:                        .getLeaf();
0827:                StatementTree statementTree = (StatementTree) statement
0828:                        .getLeaf();
0829:
0830:                int index = statements.getStatements().indexOf(statementTree);
0831:
0832:                if (index == (-1)) {
0833:                    //really strange...
0834:                    return null;
0835:                }
0836:
0837:                outPosition[0] = index;
0838:
0839:                return statements;
0840:            }
0841:
0842:            private static int[] computeInitializeIn(
0843:                    final CompilationInfo info, TreePath firstOccurrence,
0844:                    List<TreePath> occurrences) {
0845:                int[] result = new int[] { 7, 7 };
0846:                boolean inOneMethod = true;
0847:                Tree currentMethod = findMethod(firstOccurrence).getLeaf();
0848:
0849:                for (TreePath occurrence : occurrences) {
0850:                    TreePath method = findMethod(occurrence);
0851:
0852:                    if (method == null || currentMethod != method.getLeaf()) {
0853:                        inOneMethod = false;
0854:                        break;
0855:                    }
0856:                }
0857:
0858:                class Result extends RuntimeException {
0859:                    @Override
0860:                    public synchronized Throwable fillInStackTrace() {
0861:                        return null;
0862:                    }
0863:
0864:                }
0865:                class ReferencesLocalVariable extends
0866:                        TreePathScanner<Void, Void> {
0867:                    @Override
0868:                    public Void visitIdentifier(IdentifierTree node, Void p) {
0869:                        Element e = info.getTrees()
0870:                                .getElement(getCurrentPath());
0871:
0872:                        if (e != null && LOCAL_VARIABLES.contains(e.getKind())) {
0873:                            throw new Result();
0874:                        }
0875:
0876:                        return null;
0877:                    }
0878:                }
0879:
0880:                boolean referencesLocalvariables = false;
0881:
0882:                try {
0883:                    new ReferencesLocalVariable().scan(firstOccurrence, null);
0884:                } catch (Result r) {
0885:                    referencesLocalvariables = true;
0886:                }
0887:
0888:                if (!inOneMethod) {
0889:                    result[1] = IntroduceFieldPanel.INIT_FIELD
0890:                            | IntroduceFieldPanel.INIT_CONSTRUCTORS;
0891:                }
0892:
0893:                if (referencesLocalvariables) {
0894:                    result[0] = IntroduceFieldPanel.INIT_METHOD;
0895:                    result[1] = IntroduceFieldPanel.INIT_METHOD;
0896:                }
0897:
0898:                return result;
0899:            }
0900:
0901:            private static ExpressionTree expressionCopy(TreePath expression,
0902:                    WorkingCopy copy) throws IOException, BadLocationException {
0903:                //hack: creating a copy of the expression:
0904:                Document doc = copy.getDocument();
0905:                int start = (int) copy.getTrees().getSourcePositions()
0906:                        .getStartPosition(copy.getCompilationUnit(),
0907:                                expression.getLeaf());
0908:                int end = (int) copy.getTrees().getSourcePositions()
0909:                        .getEndPosition(copy.getCompilationUnit(),
0910:                                expression.getLeaf());
0911:                String text = doc.getText(start, end - start);
0912:
0913:                return copy.getTreeUtilities().parseExpression(text,
0914:                        new SourcePositions[1]);
0915:            }
0916:
0917:            private static List<ExpressionTree> realArguments(
0918:                    final TreeMaker make, List<String> parameterNames) {
0919:                List<ExpressionTree> realArguments = new LinkedList<ExpressionTree>();
0920:
0921:                for (String name : parameterNames) {
0922:                    name = name.startsWith("!") ? name.substring(1) : name;
0923:                    realArguments.add(make.Identifier(name));
0924:                }
0925:
0926:                return realArguments;
0927:            }
0928:
0929:            private static List<VariableTree> createVariables(WorkingCopy copy,
0930:                    List<TypeMirrorHandle> parameterTypes,
0931:                    List<String> parameterNames) {
0932:                final TreeMaker make = copy.getTreeMaker();
0933:                List<VariableTree> formalArguments = new LinkedList<VariableTree>();
0934:                Iterator<TypeMirrorHandle> argType = parameterTypes.iterator();
0935:                Iterator<String> argName = parameterNames.iterator();
0936:
0937:                while (argType.hasNext() && argName.hasNext()) {
0938:                    TypeMirror tm = argType.next().resolve(copy);
0939:
0940:                    if (tm == null) {
0941:                        return null;
0942:                    }
0943:
0944:                    Tree type = make.Type(tm);
0945:                    String formalArgName = argName.next();
0946:                    Set<Modifier> formalArgMods = EnumSet
0947:                            .noneOf(Modifier.class);
0948:
0949:                    if (formalArgName.startsWith("!")) {
0950:                        formalArgName = formalArgName.substring(1);
0951:                        formalArgMods.add(Modifier.FINAL);
0952:                    }
0953:
0954:                    formalArguments.add(make.Variable(make
0955:                            .Modifiers(formalArgMods), formalArgName, type,
0956:                            null));
0957:                }
0958:
0959:                return formalArguments;
0960:            }
0961:
0962:            private static List<ExpressionTree> typeHandleToTree(
0963:                    WorkingCopy copy, Set<TypeMirrorHandle> thrownTypes) {
0964:                final TreeMaker make = copy.getTreeMaker();
0965:                List<ExpressionTree> thrown = new LinkedList<ExpressionTree>();
0966:
0967:                for (TypeMirrorHandle h : thrownTypes) {
0968:                    TypeMirror t = h.resolve(copy);
0969:
0970:                    if (t == null) {
0971:                        return null;
0972:                    }
0973:
0974:                    thrown.add((ExpressionTree) make.Type(t));
0975:                }
0976:
0977:                return thrown;
0978:            }
0979:
0980:            private static final class ScanStatement extends
0981:                    TreePathScanner<Void, Void> {
0982:                private static final int PHASE_BEFORE_SELECTION = 1;
0983:                private static final int PHASE_INSIDE_SELECTION = 2;
0984:                private static final int PHASE_AFTER_SELECTION = 3;
0985:
0986:                private CompilationInfo info;
0987:                private int phase = PHASE_BEFORE_SELECTION;
0988:                private Tree firstInSelection;
0989:                private Tree lastInSelection;
0990:                private Set<VariableElement> localVariables = new HashSet<VariableElement>();
0991:                private Set<VariableElement> usedLocalVariables = new LinkedHashSet<VariableElement>();
0992:                private Set<VariableElement> selectionLocalVariables = new HashSet<VariableElement>();
0993:                private Set<VariableElement> selectionWrittenLocalVariables = new HashSet<VariableElement>();
0994:                private Set<VariableElement> usedSelectionLocalVariables = new HashSet<VariableElement>();
0995:                private Set<TreePath> selectionExits = new HashSet<TreePath>();
0996:                private Set<Tree> treesSeensInSelection = new HashSet<Tree>();
0997:                private boolean hasReturns = false;
0998:                private boolean hasBreaks = false;
0999:                private boolean hasContinues = false;
1000:                private boolean secondPass = false;
1001:                private boolean stopSecondPass = false;
1002:                private AtomicBoolean cancel;
1003:
1004:                public ScanStatement(CompilationInfo info,
1005:                        Tree firstInSelection, Tree lastInSelection,
1006:                        AtomicBoolean cancel) {
1007:                    this .info = info;
1008:                    this .firstInSelection = firstInSelection;
1009:                    this .lastInSelection = lastInSelection;
1010:                    this .cancel = cancel;
1011:                }
1012:
1013:                @Override
1014:                public Void scan(Tree tree, Void p) {
1015:                    if (stopSecondPass)
1016:                        return null;
1017:
1018:                    if (phase != PHASE_AFTER_SELECTION) {
1019:                        if (tree == firstInSelection) {
1020:                            phase = PHASE_INSIDE_SELECTION;
1021:                        }
1022:
1023:                        if (phase == PHASE_INSIDE_SELECTION) {
1024:                            treesSeensInSelection.add(tree);
1025:                        }
1026:                    }
1027:
1028:                    if (secondPass && tree == firstInSelection) {
1029:                        stopSecondPass = true;
1030:                        return null;
1031:                    }
1032:
1033:                    super .scan(tree, p);
1034:
1035:                    if (tree == lastInSelection) {
1036:                        phase = PHASE_AFTER_SELECTION;
1037:                    }
1038:
1039:                    return null;
1040:                }
1041:
1042:                @Override
1043:                public Void visitVariable(VariableTree node, Void p) {
1044:                    Element e = info.getTrees().getElement(getCurrentPath());
1045:
1046:                    if (e != null && LOCAL_VARIABLES.contains(e.getKind())) {
1047:                        switch (phase) {
1048:                        case PHASE_BEFORE_SELECTION:
1049:                            localVariables.add((VariableElement) e);
1050:                            break;
1051:                        case PHASE_INSIDE_SELECTION:
1052:                            selectionLocalVariables.add((VariableElement) e);
1053:                            break;
1054:                        }
1055:                    }
1056:
1057:                    return super .visitVariable(node, p);
1058:                }
1059:
1060:                @Override
1061:                public Void visitAssignment(AssignmentTree node, Void p) {
1062:                    if (phase == PHASE_INSIDE_SELECTION) {
1063:                        Element e = info.getTrees().getElement(
1064:                                new TreePath(getCurrentPath(), node
1065:                                        .getVariable()));
1066:
1067:                        if (e != null && LOCAL_VARIABLES.contains(e.getKind())
1068:                                && localVariables.contains(e)) {
1069:                            selectionWrittenLocalVariables
1070:                                    .add((VariableElement) e);
1071:                        }
1072:                    }
1073:
1074:                    //make sure the variable on the left side is not considered to be read:
1075:                    return scan(node.getExpression(), p);
1076:                }
1077:
1078:                @Override
1079:                public Void visitCompoundAssignment(
1080:                        CompoundAssignmentTree node, Void p) {
1081:                    if (phase == PHASE_INSIDE_SELECTION) {
1082:                        Element e = info.getTrees().getElement(
1083:                                new TreePath(getCurrentPath(), node
1084:                                        .getVariable()));
1085:
1086:                        if (e != null && LOCAL_VARIABLES.contains(e.getKind())) {
1087:                            selectionWrittenLocalVariables
1088:                                    .add((VariableElement) e);
1089:                        }
1090:                    }
1091:
1092:                    return super .visitCompoundAssignment(node, p);
1093:                }
1094:
1095:                @Override
1096:                public Void visitUnary(UnaryTree node, Void p) {
1097:                    Kind k = node.getKind();
1098:
1099:                    if (k == Kind.POSTFIX_DECREMENT
1100:                            || k == Kind.POSTFIX_INCREMENT
1101:                            || k == Kind.PREFIX_DECREMENT
1102:                            || k == Kind.PREFIX_INCREMENT) {
1103:                        //#109663:
1104:                        if (phase == PHASE_INSIDE_SELECTION) {
1105:                            Element e = info.getTrees().getElement(
1106:                                    new TreePath(getCurrentPath(), node
1107:                                            .getExpression()));
1108:
1109:                            if (e != null
1110:                                    && LOCAL_VARIABLES.contains(e.getKind())) {
1111:                                selectionWrittenLocalVariables
1112:                                        .add((VariableElement) e);
1113:                            }
1114:                        }
1115:                    }
1116:                    return super .visitUnary(node, p);
1117:                }
1118:
1119:                @Override
1120:                public Void visitIdentifier(IdentifierTree node, Void p) {
1121:                    Element e = info.getTrees().getElement(getCurrentPath());
1122:
1123:                    if (e != null) {
1124:                        if (LOCAL_VARIABLES.contains(e.getKind())) {
1125:                            switch (phase) {
1126:                            case PHASE_INSIDE_SELECTION:
1127:                                if (localVariables.contains(e)) {
1128:                                    usedLocalVariables.add((VariableElement) e);
1129:                                }
1130:                                break;
1131:                            case PHASE_AFTER_SELECTION:
1132:                                if (selectionLocalVariables.contains(e)
1133:                                        || selectionWrittenLocalVariables
1134:                                                .contains(e)) {
1135:                                    usedSelectionLocalVariables
1136:                                            .add((VariableElement) e);
1137:                                }
1138:                                break;
1139:                            }
1140:                        }
1141:                    }
1142:                    return super .visitIdentifier(node, p);
1143:                }
1144:
1145:                @Override
1146:                public Void visitReturn(ReturnTree node, Void p) {
1147:                    if (phase == PHASE_INSIDE_SELECTION) {
1148:                        selectionExits.add(getCurrentPath());
1149:                        hasReturns = true;
1150:                    }
1151:                    return super .visitReturn(node, p);
1152:                }
1153:
1154:                @Override
1155:                public Void visitBreak(BreakTree node, Void p) {
1156:                    if (phase == PHASE_INSIDE_SELECTION
1157:                            && !treesSeensInSelection.contains(info
1158:                                    .getTreeUtilities().getBreakContinueTarget(
1159:                                            getCurrentPath()))) {
1160:                        selectionExits.add(getCurrentPath());
1161:                        hasBreaks = true;
1162:                    }
1163:                    return super .visitBreak(node, p);
1164:                }
1165:
1166:                @Override
1167:                public Void visitContinue(ContinueTree node, Void p) {
1168:                    if (phase == PHASE_INSIDE_SELECTION
1169:                            && !treesSeensInSelection.contains(info
1170:                                    .getTreeUtilities().getBreakContinueTarget(
1171:                                            getCurrentPath()))) {
1172:                        selectionExits.add(getCurrentPath());
1173:                        hasContinues = true;
1174:                    }
1175:                    return super .visitContinue(node, p);
1176:                }
1177:
1178:                @Override
1179:                public Void visitWhileLoop(WhileLoopTree node, Void p) {
1180:                    super .visitWhileLoop(node, p);
1181:
1182:                    if (phase == PHASE_AFTER_SELECTION) {
1183:                        //#109663&#112552:
1184:                        //the selection was inside the while-loop, the variables inside the
1185:                        //condition&statement of the while loop need to be considered to be used again after the loop:
1186:                        secondPass = true;
1187:                        scan(node.getCondition(), p);
1188:                        scan(node.getStatement(), p);
1189:                        secondPass = false;
1190:                        stopSecondPass = false;
1191:                    }
1192:
1193:                    return null;
1194:                }
1195:
1196:                @Override
1197:                public Void visitForLoop(ForLoopTree node, Void p) {
1198:                    super .visitForLoop(node, p);
1199:
1200:                    if (phase == PHASE_AFTER_SELECTION) {
1201:                        //#109663&#112552:
1202:                        //the selection was inside the for-loop, the variables inside the
1203:                        //condition, update and statement parts of the for loop need to be considered to be used again after the loop:
1204:                        secondPass = true;
1205:                        scan(node.getCondition(), p);
1206:                        scan(node.getUpdate(), p);
1207:                        scan(node.getStatement(), p);
1208:                        secondPass = false;
1209:                        stopSecondPass = false;
1210:                    }
1211:
1212:                    return null;
1213:                }
1214:
1215:                @Override
1216:                public Void visitDoWhileLoop(DoWhileLoopTree node, Void p) {
1217:                    super .visitDoWhileLoop(node, p);
1218:
1219:                    if (phase == PHASE_AFTER_SELECTION) {
1220:                        //#109663&#112552:
1221:                        //the selection was inside the do-while, the variables inside the
1222:                        //statement part of the do-while loop need to be considered to be used again after the loop:
1223:                        secondPass = true;
1224:                        scan(node.getStatement(), p);
1225:                        secondPass = false;
1226:                        stopSecondPass = false;
1227:                    }
1228:
1229:                    return null;
1230:                }
1231:
1232:                private String verifyExits(boolean exitsFromAllBranches) {
1233:                    int i = 0;
1234:
1235:                    i += hasReturns ? 1 : 0;
1236:                    i += hasBreaks ? 1 : 0;
1237:                    i += hasContinues ? 1 : 0;
1238:
1239:                    if (i > 1) {
1240:                        return "ERR_Too_Many_Different_Exits"; // NOI18N
1241:                    }
1242:
1243:                    if ((exitsFromAllBranches ? 0 : i)
1244:                            + usedSelectionLocalVariables.size() > 1) {
1245:                        return "ERR_Too_Many_Return_Values"; // NOI18N
1246:                    }
1247:
1248:                    StatementTree breakOrContinueTarget = null;
1249:                    boolean returnValueComputed = false;
1250:                    TreePath returnValue = null;
1251:
1252:                    for (TreePath tp : selectionExits) {
1253:                        if (tp.getLeaf().getKind() == Kind.RETURN) {
1254:                            if (!exitsFromAllBranches) {
1255:                                ReturnTree rt = (ReturnTree) tp.getLeaf();
1256:                                TreePath currentReturnValue = rt
1257:                                        .getExpression() != null ? new TreePath(
1258:                                        tp, rt.getExpression())
1259:                                        : null;
1260:
1261:                                if (!returnValueComputed) {
1262:                                    returnValue = currentReturnValue;
1263:                                    returnValueComputed = true;
1264:                                } else {
1265:                                    if (returnValue != null
1266:                                            && currentReturnValue != null) {
1267:                                        List<TreePath> candidates = CopyFinder
1268:                                                .computeDuplicates(info,
1269:                                                        returnValue,
1270:                                                        currentReturnValue,
1271:                                                        cancel);
1272:
1273:                                        if (candidates.size() != 1
1274:                                                || candidates.get(0).getLeaf() != rt
1275:                                                        .getExpression()) {
1276:                                            return "ERR_Different_Return_Values"; // NOI18N
1277:                                        }
1278:                                    } else {
1279:                                        if (returnValue != currentReturnValue) {
1280:                                            return "ERR_Different_Return_Values"; // NOI18N
1281:                                        }
1282:                                    }
1283:                                }
1284:                            }
1285:                        } else {
1286:                            StatementTree target = info.getTreeUtilities()
1287:                                    .getBreakContinueTarget(tp);
1288:
1289:                            if (breakOrContinueTarget == null) {
1290:                                breakOrContinueTarget = target;
1291:                            }
1292:
1293:                            if (breakOrContinueTarget != target)
1294:                                return "ERR_Break_Mismatch"; // NOI18N
1295:                        }
1296:                    }
1297:
1298:                    return null;
1299:                }
1300:            }
1301:
1302:            private static final class ExitsFromAllBranches extends
1303:                    TreePathScanner<Boolean, Void> {
1304:
1305:                private CompilationInfo info;
1306:                private Set<Tree> seenTrees = new HashSet<Tree>();
1307:
1308:                public ExitsFromAllBranches(CompilationInfo info) {
1309:                    this .info = info;
1310:                }
1311:
1312:                @Override
1313:                public Boolean scan(Tree tree, Void p) {
1314:                    seenTrees.add(tree);
1315:                    return super .scan(tree, p);
1316:                }
1317:
1318:                @Override
1319:                public Boolean visitIf(IfTree node, Void p) {
1320:                    return scan(node.getThenStatement(), null) == Boolean.TRUE
1321:                            && scan(node.getElseStatement(), null) == Boolean.TRUE;
1322:                }
1323:
1324:                @Override
1325:                public Boolean visitReturn(ReturnTree node, Void p) {
1326:                    return true;
1327:                }
1328:
1329:                @Override
1330:                public Boolean visitBreak(BreakTree node, Void p) {
1331:                    return !seenTrees.contains(info.getTreeUtilities()
1332:                            .getBreakContinueTarget(getCurrentPath()));
1333:                }
1334:
1335:                @Override
1336:                public Boolean visitContinue(ContinueTree node, Void p) {
1337:                    return !seenTrees.contains(info.getTreeUtilities()
1338:                            .getBreakContinueTarget(getCurrentPath()));
1339:                }
1340:
1341:                @Override
1342:                public Boolean visitClass(ClassTree node, Void p) {
1343:                    return false;
1344:                }
1345:
1346:            }
1347:
1348:            private static final class IntroduceFix implements  Fix {
1349:
1350:                private String guessedName;
1351:                private TreePathHandle handle;
1352:                private JavaSource js;
1353:                private int numDuplicates;
1354:                private IntroduceKind kind;
1355:
1356:                public IntroduceFix(TreePathHandle handle, JavaSource js,
1357:                        String guessedName, int numDuplicates,
1358:                        IntroduceKind kind) {
1359:                    this .handle = handle;
1360:                    this .js = js;
1361:                    this .guessedName = guessedName;
1362:                    this .numDuplicates = numDuplicates;
1363:                    this .kind = kind;
1364:                }
1365:
1366:                @Override
1367:                public String toString() {
1368:                    return "[IntroduceFix:" + guessedName + ":" + numDuplicates
1369:                            + ":" + kind + "]"; // NOI18N
1370:                }
1371:
1372:                public String getKeyExt() {
1373:                    switch (kind) {
1374:                    case CREATE_CONSTANT:
1375:                        return "IntroduceConstant"; //NOI18N
1376:                    case CREATE_VARIABLE:
1377:                        return "IntroduceVariable"; //NOI18N
1378:                    default:
1379:                        throw new IllegalStateException();
1380:                    }
1381:                }
1382:
1383:                public String getText() {
1384:                    return NbBundle.getMessage(IntroduceHint.class, "FIX_"
1385:                            + getKeyExt()); //NOI18N
1386:                }
1387:
1388:                public ChangeInfo implement() throws IOException,
1389:                        BadLocationException {
1390:                    JButton btnOk = new JButton(NbBundle.getMessage(
1391:                            IntroduceHint.class, "LBL_Ok"));
1392:                    JButton btnCancel = new JButton(NbBundle.getMessage(
1393:                            IntroduceHint.class, "LBL_Cancel"));
1394:                    IntroduceVariablePanel panel = new IntroduceVariablePanel(
1395:                            numDuplicates, guessedName,
1396:                            kind == IntroduceKind.CREATE_CONSTANT, btnOk);
1397:                    String caption = NbBundle.getMessage(IntroduceHint.class,
1398:                            "CAP_" + getKeyExt()); //NOI18N
1399:                    DialogDescriptor dd = new DialogDescriptor(panel, caption,
1400:                            true, new Object[] { btnOk, btnCancel }, btnOk,
1401:                            DialogDescriptor.DEFAULT_ALIGN, null, null);
1402:                    if (DialogDisplayer.getDefault().notify(dd) != btnOk) {
1403:                        return null;//cancel
1404:                    }
1405:                    final String name = panel.getVariableName();
1406:                    final boolean replaceAll = panel.isReplaceAll();
1407:                    final boolean declareFinal = panel.isDeclareFinal();
1408:                    final Set<Modifier> access = kind == IntroduceKind.CREATE_CONSTANT ? panel
1409:                            .getAccess()
1410:                            : null;
1411:                    js.runModificationTask(new Task<WorkingCopy>() {
1412:                        public void run(WorkingCopy parameter) throws Exception {
1413:                            parameter.toPhase(Phase.RESOLVED);
1414:
1415:                            TreePath resolved = handle.resolve(parameter);
1416:                            TypeMirror tm = parameter.getTrees().getTypeMirror(
1417:                                    resolved);
1418:
1419:                            if (resolved == null || tm == null) {
1420:                                return; //TODO...
1421:                            }
1422:
1423:                            tm = Utilities.resolveCapturedType(parameter, tm);
1424:
1425:                            //hack: creating a copy of the expression:
1426:                            ExpressionTree expressionCopy = expressionCopy(
1427:                                    resolved, parameter);
1428:                            ModifiersTree mods;
1429:                            final TreeMaker make = parameter.getTreeMaker();
1430:
1431:                            switch (kind) {
1432:                            case CREATE_CONSTANT:
1433:                                //find first class:
1434:                                TreePath pathToClass = resolved;
1435:
1436:                                while (pathToClass != null
1437:                                        && pathToClass.getLeaf().getKind() != Kind.CLASS) {
1438:                                    pathToClass = pathToClass.getParentPath();
1439:                                }
1440:
1441:                                if (pathToClass == null) {
1442:                                    return; //TODO...
1443:                                }
1444:
1445:                                Set<Modifier> localAccess = EnumSet.of(
1446:                                        Modifier.FINAL, Modifier.STATIC);
1447:
1448:                                localAccess.addAll(access);
1449:
1450:                                mods = make.Modifiers(localAccess);
1451:
1452:                                VariableTree constant = make.Variable(mods,
1453:                                        name, make.Type(tm), expressionCopy);
1454:                                ClassTree nueClass = GeneratorUtils
1455:                                        .insertClassMember(parameter,
1456:                                                pathToClass, constant);
1457:
1458:                                parameter.rewrite(pathToClass.getLeaf(),
1459:                                        nueClass);
1460:
1461:                                if (replaceAll) {
1462:                                    for (TreePath p : CopyFinder
1463:                                            .computeDuplicates(
1464:                                                    parameter,
1465:                                                    resolved,
1466:                                                    new TreePath(
1467:                                                            parameter
1468:                                                                    .getCompilationUnit()),
1469:                                                    new AtomicBoolean())) {
1470:                                        parameter.rewrite(p.getLeaf(), make
1471:                                                .Identifier(name));
1472:                                    }
1473:                                }
1474:                                break;
1475:                            case CREATE_VARIABLE:
1476:                                TreePath method = findMethod(resolved);
1477:
1478:                                if (method == null) {
1479:                                    return; //TODO...
1480:                                }
1481:
1482:                                BlockTree statements;
1483:                                int index;
1484:
1485:                                if (replaceAll) {
1486:                                    List<TreePath> candidates = CopyFinder
1487:                                            .computeDuplicates(parameter,
1488:                                                    resolved, method,
1489:                                                    new AtomicBoolean());
1490:                                    for (TreePath p : candidates) {
1491:                                        Tree leaf = p.getLeaf();
1492:
1493:                                        parameter.rewrite(leaf, make
1494:                                                .Identifier(name));
1495:                                    }
1496:
1497:                                    int[] out = new int[1];
1498:                                    statements = findAddPosition(parameter,
1499:                                            resolved, candidates, out);
1500:
1501:                                    if (statements == null) {
1502:                                        return;
1503:                                    }
1504:
1505:                                    index = out[0];
1506:                                } else {
1507:                                    int[] out = new int[1];
1508:                                    statements = findAddPosition(parameter,
1509:                                            resolved, Collections
1510:                                                    .<TreePath> emptyList(),
1511:                                            out);
1512:
1513:                                    if (statements == null) {
1514:                                        return;
1515:                                    }
1516:
1517:                                    index = out[0];
1518:                                }
1519:
1520:                                List<StatementTree> nueStatements = new LinkedList<StatementTree>(
1521:                                        statements.getStatements());
1522:                                mods = make.Modifiers(declareFinal ? EnumSet
1523:                                        .of(Modifier.FINAL) : EnumSet
1524:                                        .noneOf(Modifier.class));
1525:
1526:                                nueStatements
1527:                                        .add(
1528:                                                index,
1529:                                                make
1530:                                                        .Variable(mods, name,
1531:                                                                make.Type(tm),
1532:                                                                expressionCopy/*(ExpressionTree) resolved.getLeaf()*//*(ExpressionTree) resolved.getLeaf()*/));
1533:
1534:                                BlockTree nueBlock = make.Block(nueStatements,
1535:                                        false);
1536:
1537:                                parameter.rewrite(statements, nueBlock);
1538:                                break;
1539:                            }
1540:
1541:                            parameter.rewrite(resolved.getLeaf(), make
1542:                                    .Identifier(name));
1543:                        }
1544:                    }).commit();
1545:                    return null;
1546:                }
1547:            }
1548:
1549:            private static final class IntroduceFieldFix implements  Fix {
1550:
1551:                private String guessedName;
1552:                private TreePathHandle handle;
1553:                private JavaSource js;
1554:                private int numDuplicates;
1555:                private int[] initilizeIn;
1556:                private boolean statik;
1557:                private boolean allowFinalInCurrentMethod;
1558:
1559:                public IntroduceFieldFix(TreePathHandle handle, JavaSource js,
1560:                        String guessedName, int numDuplicates,
1561:                        int[] initilizeIn, boolean statik,
1562:                        boolean allowFinalInCurrentMethod) {
1563:                    this .handle = handle;
1564:                    this .js = js;
1565:                    this .guessedName = guessedName;
1566:                    this .numDuplicates = numDuplicates;
1567:                    this .initilizeIn = initilizeIn;
1568:                    this .statik = statik;
1569:                    this .allowFinalInCurrentMethod = allowFinalInCurrentMethod;
1570:                }
1571:
1572:                public String getText() {
1573:                    return NbBundle.getMessage(IntroduceHint.class,
1574:                            "FIX_IntroduceField");
1575:                }
1576:
1577:                @Override
1578:                public String toString() {
1579:                    return "[IntroduceField:" + guessedName + ":"
1580:                            + numDuplicates + ":" + statik + ":"
1581:                            + allowFinalInCurrentMethod + ":"
1582:                            + Arrays.toString(initilizeIn) + "]"; // NOI18N
1583:                }
1584:
1585:                public ChangeInfo implement() throws IOException,
1586:                        BadLocationException {
1587:                    JButton btnOk = new JButton(NbBundle.getMessage(
1588:                            IntroduceHint.class, "LBL_Ok"));
1589:                    btnOk.getAccessibleContext().setAccessibleDescription(
1590:                            NbBundle.getMessage(IntroduceHint.class,
1591:                                    "AD_IntrHint_OK"));
1592:                    JButton btnCancel = new JButton(NbBundle.getMessage(
1593:                            IntroduceHint.class, "LBL_Cancel"));
1594:                    btnCancel.getAccessibleContext().setAccessibleDescription(
1595:                            NbBundle.getMessage(IntroduceHint.class,
1596:                                    "AD_IntrHint_Cancel"));
1597:                    IntroduceFieldPanel panel = new IntroduceFieldPanel(
1598:                            guessedName, initilizeIn, numDuplicates,
1599:                            allowFinalInCurrentMethod, btnOk);
1600:                    String caption = NbBundle.getMessage(IntroduceHint.class,
1601:                            "CAP_IntroduceField");
1602:                    DialogDescriptor dd = new DialogDescriptor(panel, caption,
1603:                            true, new Object[] { btnOk, btnCancel }, btnOk,
1604:                            DialogDescriptor.DEFAULT_ALIGN, null, null);
1605:                    if (DialogDisplayer.getDefault().notify(dd) != btnOk) {
1606:                        return null;//cancel
1607:                    }
1608:                    final String name = panel.getFieldName();
1609:                    final boolean replaceAll = panel.isReplaceAll();
1610:                    final boolean declareFinal = panel.isDeclareFinal();
1611:                    final Set<Modifier> access = panel.getAccess();
1612:                    final int initializeIn = panel.getInitializeIn();
1613:                    js.runModificationTask(new Task<WorkingCopy>() {
1614:                        public void run(WorkingCopy parameter) throws Exception {
1615:                            parameter.toPhase(Phase.RESOLVED);
1616:
1617:                            TreePath resolved = handle.resolve(parameter);
1618:                            TypeMirror tm = parameter.getTrees().getTypeMirror(
1619:                                    resolved);
1620:
1621:                            if (resolved == null || tm == null) {
1622:                                return; //TODO...
1623:                            }
1624:
1625:                            tm = Utilities.resolveCapturedType(parameter, tm);
1626:
1627:                            TreePath pathToClass = resolved;
1628:
1629:                            while (pathToClass != null
1630:                                    && pathToClass.getLeaf().getKind() != Kind.CLASS) {
1631:                                pathToClass = pathToClass.getParentPath();
1632:                            }
1633:
1634:                            if (pathToClass == null) {
1635:                                return; //TODO...
1636:                            }
1637:
1638:                            //hack: creating a copy of the expression:
1639:                            Document doc = parameter.getDocument();
1640:                            int start = (int) parameter.getTrees()
1641:                                    .getSourcePositions().getStartPosition(
1642:                                            parameter.getCompilationUnit(),
1643:                                            resolved.getLeaf());
1644:                            int end = (int) parameter.getTrees()
1645:                                    .getSourcePositions().getEndPosition(
1646:                                            parameter.getCompilationUnit(),
1647:                                            resolved.getLeaf());
1648:                            String text = doc.getText(start, end - start);
1649:                            ExpressionTree expressionCopy = parameter
1650:                                    .getTreeUtilities().parseExpression(text,
1651:                                            new SourcePositions[1]);
1652:
1653:                            Set<Modifier> mods = declareFinal ? EnumSet
1654:                                    .of(Modifier.FINAL) : EnumSet
1655:                                    .noneOf(Modifier.class);
1656:
1657:                            if (statik) {
1658:                                mods.add(Modifier.STATIC);
1659:                            }
1660:
1661:                            mods.addAll(access);
1662:                            final TreeMaker make = parameter.getTreeMaker();
1663:
1664:                            boolean isAnyOccurenceStatic = false;
1665:
1666:                            if (replaceAll) {
1667:                                for (TreePath p : CopyFinder.computeDuplicates(
1668:                                        parameter, resolved,
1669:                                        new TreePath(parameter
1670:                                                .getCompilationUnit()),
1671:                                        new AtomicBoolean())) {
1672:                                    parameter.rewrite(p.getLeaf(), make
1673:                                            .Identifier(name));
1674:                                    Scope occurenceScope = parameter.getTrees()
1675:                                            .getScope(p);
1676:                                    if (parameter.getTreeUtilities()
1677:                                            .isStaticContext(occurenceScope))
1678:                                        isAnyOccurenceStatic = true;
1679:
1680:                                }
1681:                            }
1682:
1683:                            if (!statik && isAnyOccurenceStatic) {
1684:                                mods.add(Modifier.STATIC);
1685:                            }
1686:
1687:                            ModifiersTree modsTree = make.Modifiers(mods);
1688:
1689:                            VariableTree field = make
1690:                                    .Variable(
1691:                                            modsTree,
1692:                                            name,
1693:                                            make.Type(tm),
1694:                                            initializeIn == IntroduceFieldPanel.INIT_FIELD ? expressionCopy
1695:                                                    : null);
1696:                            ClassTree nueClass = GeneratorUtils
1697:                                    .insertClassMember(parameter, pathToClass,
1698:                                            field);
1699:
1700:                            parameter.rewrite(resolved.getLeaf(), make
1701:                                    .Identifier(name));
1702:
1703:                            TreePath method = findMethod(resolved);
1704:
1705:                            if (method == null) {
1706:                                return; //TODO...
1707:                            }
1708:
1709:                            if (initializeIn == IntroduceFieldPanel.INIT_METHOD) {
1710:                                TreePath statementPath = resolved;
1711:
1712:                                statementPath = findStatement(statementPath);
1713:
1714:                                if (statementPath == null) {
1715:                                    //XXX: well....
1716:                                    return;
1717:                                }
1718:
1719:                                BlockTree statements = (BlockTree) statementPath
1720:                                        .getParentPath().getLeaf();
1721:                                StatementTree statement = (StatementTree) statementPath
1722:                                        .getLeaf();
1723:
1724:                                int index = statements.getStatements().indexOf(
1725:                                        statement);
1726:
1727:                                if (index == (-1)) {
1728:                                    //really strange...
1729:                                    return;
1730:                                }
1731:
1732:                                List<StatementTree> nueStatements = new LinkedList<StatementTree>(
1733:                                        statements.getStatements());
1734:
1735:                                nueStatements.add(index, make
1736:                                        .ExpressionStatement(make.Assignment(
1737:                                                make.Identifier(name),
1738:                                                expressionCopy)));
1739:
1740:                                BlockTree nueBlock = make.Block(nueStatements,
1741:                                        false);
1742:
1743:                                parameter.rewrite(statements, nueBlock);
1744:                            }
1745:
1746:                            if (initializeIn == IntroduceFieldPanel.INIT_CONSTRUCTORS) {
1747:                                for (TreePath constructor : findConstructors(
1748:                                        parameter, method)) {
1749:                                    //check for syntetic constructor:
1750:                                    if (parameter.getTreeUtilities()
1751:                                            .isSynthetic(constructor)) {
1752:                                        List<StatementTree> nueStatements = new LinkedList<StatementTree>();
1753:                                        ExpressionTree reference = make
1754:                                                .Identifier(name);
1755:                                        Element clazz = parameter.getTrees()
1756:                                                .getElement(pathToClass);
1757:                                        ModifiersTree constrMods = clazz
1758:                                                .getKind() != ElementKind.ENUM ? make
1759:                                                .Modifiers(EnumSet
1760:                                                        .of(Modifier.PUBLIC))
1761:                                                : make
1762:                                                        .Modifiers(Collections.EMPTY_SET);
1763:
1764:                                        nueStatements
1765:                                                .add(make
1766:                                                        .ExpressionStatement(make
1767:                                                                .Assignment(
1768:                                                                        reference,
1769:                                                                        expressionCopy)));
1770:
1771:                                        BlockTree nueBlock = make.Block(
1772:                                                nueStatements, false);
1773:                                        MethodTree nueConstr = make
1774:                                                .Method(
1775:                                                        constrMods,
1776:                                                        "<init>",
1777:                                                        null,
1778:                                                        Collections
1779:                                                                .<TypeParameterTree> emptyList(),
1780:                                                        Collections
1781:                                                                .<VariableTree> emptyList(),
1782:                                                        Collections
1783:                                                                .<ExpressionTree> emptyList(),
1784:                                                        nueBlock, null); //NOI18N
1785:
1786:                                        nueClass = GeneratorUtils
1787:                                                .insertClassMember(
1788:                                                        parameter,
1789:                                                        new TreePath(
1790:                                                                new TreePath(
1791:                                                                        parameter
1792:                                                                                .getCompilationUnit()),
1793:                                                                nueClass),
1794:                                                        nueConstr);
1795:
1796:                                        nueClass = make
1797:                                                .removeClassMember(nueClass,
1798:                                                        constructor.getLeaf());
1799:                                        break;
1800:                                    }
1801:
1802:                                    boolean hasParameterOfTheSameName = false;
1803:                                    MethodTree constr = ((MethodTree) constructor
1804:                                            .getLeaf());
1805:
1806:                                    for (VariableTree p : constr
1807:                                            .getParameters()) {
1808:                                        if (name.equals(p.getName().toString())) {
1809:                                            hasParameterOfTheSameName = true;
1810:                                            break;
1811:                                        }
1812:                                    }
1813:
1814:                                    BlockTree origBody = constr.getBody();
1815:                                    List<StatementTree> nueStatements = new LinkedList<StatementTree>();
1816:                                    ExpressionTree reference = hasParameterOfTheSameName ? make
1817:                                            .MemberSelect(make
1818:                                                    .Identifier("this"), name)
1819:                                            : make.Identifier(name); // NOI18N
1820:
1821:                                    List<? extends StatementTree> origStatements = origBody
1822:                                            .getStatements();
1823:                                    StatementTree canBeSuper = origStatements
1824:                                            .get(0);
1825:                                    if (!parameter.getTreeUtilities()
1826:                                            .isSynthetic(
1827:                                                    TreePath.getPath(
1828:                                                            constructor,
1829:                                                            canBeSuper))) {
1830:                                        nueStatements.add(canBeSuper);
1831:                                    }
1832:                                    nueStatements.add(make
1833:                                            .ExpressionStatement(make
1834:                                                    .Assignment(reference,
1835:                                                            expressionCopy)));
1836:                                    nueStatements.addAll(origStatements
1837:                                            .subList(1, origStatements.size()));
1838:
1839:                                    BlockTree nueBlock = make.Block(
1840:                                            nueStatements, false);
1841:
1842:                                    parameter.rewrite(origBody, nueBlock);
1843:                                }
1844:                            }
1845:
1846:                            parameter.rewrite(pathToClass.getLeaf(), nueClass);
1847:                        }
1848:                    }).commit();
1849:                    return null;
1850:                }
1851:            }
1852:
1853:            private static final class IntroduceMethodFix implements  Fix {
1854:
1855:                private JavaSource js;
1856:
1857:                private TreePathHandle parentBlock;
1858:                private List<TypeMirrorHandle> parameterTypes;
1859:                private List<String> parameterNames;
1860:                private List<TypeMirrorHandle> additionalLocalTypes;
1861:                private List<String> additionalLocalNames;
1862:                private TypeMirrorHandle returnType;
1863:                private String returnName;
1864:                private boolean declareVariableForReturnValue;
1865:                private Set<TypeMirrorHandle> thrownTypes;
1866:                private List<TreePathHandle> exists;
1867:                private boolean exitsFromAllBranches;
1868:                private int from;
1869:                private int to;
1870:
1871:                public IntroduceMethodFix(JavaSource js,
1872:                        TreePathHandle parentBlock,
1873:                        List<TypeMirrorHandle> parameterTypes,
1874:                        List<String> parameterNames,
1875:                        List<TypeMirrorHandle> additionalLocalTypes,
1876:                        List<String> additionalLocalNames,
1877:                        TypeMirrorHandle returnType, String returnName,
1878:                        boolean declareVariableForReturnValue,
1879:                        Set<TypeMirrorHandle> thrownTypes,
1880:                        List<TreePathHandle> exists,
1881:                        boolean exitsFromAllBranches, int from, int to) {
1882:                    this .js = js;
1883:                    this .parentBlock = parentBlock;
1884:                    this .parameterTypes = parameterTypes;
1885:                    this .parameterNames = parameterNames;
1886:                    this .additionalLocalTypes = additionalLocalTypes;
1887:                    this .additionalLocalNames = additionalLocalNames;
1888:                    this .returnType = returnType;
1889:                    this .returnName = returnName;
1890:                    this .declareVariableForReturnValue = declareVariableForReturnValue;
1891:                    this .thrownTypes = thrownTypes;
1892:                    this .exists = exists;
1893:                    this .exitsFromAllBranches = exitsFromAllBranches;
1894:                    this .from = from;
1895:                    this .to = to;
1896:                }
1897:
1898:                public String getText() {
1899:                    return NbBundle.getMessage(IntroduceHint.class,
1900:                            "FIX_IntroduceMethod");
1901:                }
1902:
1903:                public String toDebugString(CompilationInfo info) {
1904:                    return "[IntroduceMethod:" + from + ":" + to + "]"; // NOI18N
1905:                }
1906:
1907:                public ChangeInfo implement() throws Exception {
1908:                    JButton btnOk = new JButton(NbBundle.getMessage(
1909:                            IntroduceHint.class, "LBL_Ok"));
1910:                    JButton btnCancel = new JButton(NbBundle.getMessage(
1911:                            IntroduceHint.class, "LBL_Cancel"));
1912:                    IntroduceMethodPanel panel = new IntroduceMethodPanel(""); //NOI18N
1913:                    panel.setOkButton(btnOk);
1914:                    String caption = NbBundle.getMessage(IntroduceHint.class,
1915:                            "CAP_IntroduceMethod");
1916:                    DialogDescriptor dd = new DialogDescriptor(panel, caption,
1917:                            true, new Object[] { btnOk, btnCancel }, btnOk,
1918:                            DialogDescriptor.DEFAULT_ALIGN, null, null);
1919:                    if (DialogDisplayer.getDefault().notify(dd) != btnOk) {
1920:                        return null;//cancel
1921:                    }
1922:                    final String name = panel.getMethodName();
1923:                    final Set<Modifier> access = panel.getAccess();
1924:
1925:                    js.runModificationTask(new Task<WorkingCopy>() {
1926:                        public void run(WorkingCopy copy) throws Exception {
1927:                            copy.toPhase(Phase.RESOLVED);
1928:
1929:                            TreePath block = parentBlock.resolve(copy);
1930:                            TypeMirror returnType = IntroduceMethodFix.this .returnType
1931:                                    .resolve(copy);
1932:
1933:                            if (block == null || returnType == null) {
1934:                                return; //TODO...
1935:                            }
1936:
1937:                            Scope s = copy.getTrees().getScope(block);
1938:                            boolean isStatic = copy.getTreeUtilities()
1939:                                    .isStaticContext(s);
1940:                            BlockTree statements = (BlockTree) block.getLeaf();
1941:                            List<StatementTree> nueStatements = new LinkedList<StatementTree>();
1942:
1943:                            nueStatements.addAll(statements.getStatements()
1944:                                    .subList(0, from));
1945:
1946:                            final TreeMaker make = copy.getTreeMaker();
1947:                            List<ExpressionTree> realArguments = realArguments(
1948:                                    make, parameterNames);
1949:
1950:                            List<StatementTree> methodStatements = new LinkedList<StatementTree>();
1951:
1952:                            Iterator<TypeMirrorHandle> additionalType = additionalLocalTypes
1953:                                    .iterator();
1954:                            Iterator<String> additionalName = additionalLocalNames
1955:                                    .iterator();
1956:
1957:                            while (additionalType.hasNext()
1958:                                    && additionalName.hasNext()) {
1959:                                TypeMirror tm = additionalType.next().resolve(
1960:                                        copy);
1961:
1962:                                if (tm == null) {
1963:                                    //XXX:
1964:                                    return;
1965:                                }
1966:
1967:                                Tree type = make.Type(tm);
1968:
1969:                                methodStatements.add(make.Variable(make
1970:                                        .Modifiers(EnumSet
1971:                                                .noneOf(Modifier.class)),
1972:                                        additionalName.next(), type, null));
1973:                            }
1974:
1975:                            methodStatements.addAll(statements.getStatements()
1976:                                    .subList(from, to + 1));
1977:
1978:                            Tree returnTypeTree = make.Type(returnType);
1979:                            ExpressionTree invocation = make.MethodInvocation(
1980:                                    Collections.<ExpressionTree> emptyList(),
1981:                                    make.Identifier(name), realArguments);
1982:
1983:                            ReturnTree ret = null;
1984:
1985:                            if (returnName != null) {
1986:                                ret = make.Return(make.Identifier(returnName));
1987:                                if (declareVariableForReturnValue) {
1988:                                    nueStatements.add(make.Variable(make
1989:                                            .Modifiers(EnumSet
1990:                                                    .noneOf(Modifier.class)),
1991:                                            returnName, returnTypeTree,
1992:                                            invocation));
1993:                                    invocation = null;
1994:                                } else {
1995:                                    invocation = make
1996:                                            .Assignment(make
1997:                                                    .Identifier(returnName),
1998:                                                    invocation);
1999:                                }
2000:                            }
2001:
2002:                            if (!exists.isEmpty()) {
2003:                                TreePath handle = null;
2004:
2005:                                handle = exists.iterator().next().resolve(copy);
2006:
2007:                                if (handle == null) {
2008:                                    return; //TODO...
2009:                                }
2010:
2011:                                assert handle != null;
2012:
2013:                                if (exitsFromAllBranches
2014:                                        && handle.getLeaf().getKind() == Kind.RETURN) {
2015:                                    nueStatements.add(make.Return(invocation));
2016:                                } else {
2017:                                    if (ret == null) {
2018:                                        if (exitsFromAllBranches) {
2019:                                            ret = make.Return(null);
2020:                                        } else {
2021:                                            ret = make.Return(make
2022:                                                    .Literal(true));
2023:                                        }
2024:                                    }
2025:
2026:                                    for (TreePathHandle h : exists) {
2027:                                        TreePath resolved = h.resolve(copy);
2028:
2029:                                        if (resolved == null) {
2030:                                            return; //TODO...
2031:                                        }
2032:
2033:                                        copy.rewrite(resolved.getLeaf(), ret);
2034:                                    }
2035:
2036:                                    StatementTree branch = null;
2037:
2038:                                    switch (handle.getLeaf().getKind()) {
2039:                                    case BREAK:
2040:                                        branch = make.Break(((BreakTree) handle
2041:                                                .getLeaf()).getLabel());
2042:                                        break;
2043:                                    case CONTINUE:
2044:                                        branch = make
2045:                                                .Continue(((ContinueTree) handle
2046:                                                        .getLeaf()).getLabel());
2047:                                        break;
2048:                                    case RETURN:
2049:                                        branch = make
2050:                                                .Return(((ReturnTree) handle
2051:                                                        .getLeaf())
2052:                                                        .getExpression());
2053:                                        break;
2054:                                    }
2055:
2056:                                    if (returnName != null
2057:                                            || exitsFromAllBranches) {
2058:                                        nueStatements
2059:                                                .add(make
2060:                                                        .ExpressionStatement(invocation));
2061:                                        nueStatements.add(branch);
2062:                                    } else {
2063:                                        nueStatements.add(make.If(make
2064:                                                .Parenthesized(invocation),
2065:                                                branch, null));
2066:                                        methodStatements.add(make.Return(make
2067:                                                .Literal(false)));
2068:                                    }
2069:                                }
2070:
2071:                                invocation = null;
2072:                            } else {
2073:                                if (ret != null) {
2074:                                    methodStatements.add(ret);
2075:                                }
2076:                            }
2077:
2078:                            if (invocation != null)
2079:                                nueStatements.add(make
2080:                                        .ExpressionStatement(invocation));
2081:
2082:                            nueStatements.addAll(statements.getStatements()
2083:                                    .subList(to + 1,
2084:                                            statements.getStatements().size()));
2085:
2086:                            Set<Modifier> modifiers = EnumSet
2087:                                    .noneOf(Modifier.class);
2088:
2089:                            if (isStatic) {
2090:                                modifiers.add(Modifier.STATIC);
2091:                            }
2092:
2093:                            modifiers.addAll(access);
2094:
2095:                            ModifiersTree mods = make.Modifiers(modifiers);
2096:                            List<VariableTree> formalArguments = createVariables(
2097:                                    copy, parameterTypes, parameterNames);
2098:
2099:                            if (formalArguments == null) {
2100:                                return; //XXX
2101:                            }
2102:
2103:                            List<ExpressionTree> thrown = typeHandleToTree(
2104:                                    copy, thrownTypes);
2105:
2106:                            if (thrownTypes == null) {
2107:                                return; //XXX
2108:                            }
2109:
2110:                            MethodTree method = make.Method(mods, name,
2111:                                    returnTypeTree, Collections
2112:                                            .<TypeParameterTree> emptyList(),
2113:                                    formalArguments, thrown, make.Block(
2114:                                            methodStatements, false), null);
2115:
2116:                            TreePath pathToClass = findClass(block);
2117:
2118:                            assert pathToClass != null;
2119:
2120:                            ClassTree nueClass = GeneratorUtils
2121:                                    .insertClassMember(copy, pathToClass,
2122:                                            method);
2123:
2124:                            copy.rewrite(pathToClass.getLeaf(), nueClass);
2125:                            copy.rewrite(statements, make.Block(nueStatements,
2126:                                    statements.isStatic()));
2127:                        }
2128:                    }).commit();
2129:
2130:                    return null;
2131:                }
2132:
2133:            }
2134:
2135:            private static final class IntroduceExpressionBasedMethodFix
2136:                    implements  Fix {
2137:
2138:                private JavaSource js;
2139:
2140:                private TreePathHandle expression;
2141:                private List<TypeMirrorHandle> parameterTypes;
2142:                private List<String> parameterNames;
2143:                private Set<TypeMirrorHandle> thrownTypes;
2144:
2145:                public IntroduceExpressionBasedMethodFix(JavaSource js,
2146:                        TreePathHandle expression,
2147:                        List<TypeMirrorHandle> parameterTypes,
2148:                        List<String> parameterNames,
2149:                        Set<TypeMirrorHandle> thrownTypes) {
2150:                    this .js = js;
2151:                    this .expression = expression;
2152:                    this .parameterTypes = parameterTypes;
2153:                    this .parameterNames = parameterNames;
2154:                    this .thrownTypes = thrownTypes;
2155:                }
2156:
2157:                public String getText() {
2158:                    return NbBundle.getMessage(IntroduceHint.class,
2159:                            "FIX_IntroduceMethod");
2160:                }
2161:
2162:                public String toString() {
2163:                    return "[IntroduceExpressionBasedMethodFix]"; // NOI18N
2164:                }
2165:
2166:                public ChangeInfo implement() throws Exception {
2167:                    JButton btnOk = new JButton(NbBundle.getMessage(
2168:                            IntroduceHint.class, "LBL_Ok"));
2169:                    JButton btnCancel = new JButton(NbBundle.getMessage(
2170:                            IntroduceHint.class, "LBL_Cancel"));
2171:                    IntroduceMethodPanel panel = new IntroduceMethodPanel(""); //NOI18N
2172:                    panel.setOkButton(btnOk);
2173:                    String caption = NbBundle.getMessage(IntroduceHint.class,
2174:                            "CAP_IntroduceMethod");
2175:                    DialogDescriptor dd = new DialogDescriptor(panel, caption,
2176:                            true, new Object[] { btnOk, btnCancel }, btnOk,
2177:                            DialogDescriptor.DEFAULT_ALIGN, null, null);
2178:                    if (DialogDisplayer.getDefault().notify(dd) != btnOk) {
2179:                        return null;//cancel
2180:                    }
2181:                    final String name = panel.getMethodName();
2182:                    final Set<Modifier> access = panel.getAccess();
2183:
2184:                    js.runModificationTask(new Task<WorkingCopy>() {
2185:                        public void run(WorkingCopy copy) throws Exception {
2186:                            copy.toPhase(Phase.RESOLVED);
2187:
2188:                            TreePath expression = IntroduceExpressionBasedMethodFix.this .expression
2189:                                    .resolve(copy);
2190:                            TypeMirror returnType = expression != null ? copy
2191:                                    .getTrees().getTypeMirror(expression)
2192:                                    : null;
2193:
2194:                            if (expression == null || returnType == null) {
2195:                                return; //TODO...
2196:                            }
2197:
2198:                            returnType = Utilities.resolveCapturedType(copy,
2199:                                    returnType);
2200:                            ExpressionTree expressionCopy = expressionCopy(
2201:                                    expression, copy);
2202:
2203:                            final TreeMaker make = copy.getTreeMaker();
2204:                            Tree returnTypeTree = make.Type(returnType);
2205:                            List<ExpressionTree> realArguments = realArguments(
2206:                                    make, parameterNames);
2207:
2208:                            ExpressionTree invocation = make.MethodInvocation(
2209:                                    Collections.<ExpressionTree> emptyList(),
2210:                                    make.Identifier(name), realArguments);
2211:
2212:                            Scope s = copy.getTrees().getScope(expression);
2213:                            boolean isStatic = copy.getTreeUtilities()
2214:                                    .isStaticContext(s);
2215:
2216:                            Set<Modifier> modifiers = EnumSet
2217:                                    .noneOf(Modifier.class);
2218:
2219:                            if (isStatic) {
2220:                                modifiers.add(Modifier.STATIC);
2221:                            }
2222:
2223:                            modifiers.addAll(access);
2224:
2225:                            ModifiersTree mods = make.Modifiers(modifiers);
2226:                            List<VariableTree> formalArguments = createVariables(
2227:                                    copy, parameterTypes, parameterNames);
2228:
2229:                            if (formalArguments == null) {
2230:                                return; //XXX
2231:                            }
2232:
2233:                            List<ExpressionTree> thrown = typeHandleToTree(
2234:                                    copy, thrownTypes);
2235:
2236:                            if (thrownTypes == null) {
2237:                                return; //XXX
2238:                            }
2239:
2240:                            List<StatementTree> methodStatements = new LinkedList<StatementTree>();
2241:
2242:                            methodStatements.add(make.Return(expressionCopy));
2243:
2244:                            MethodTree method = make.Method(mods, name,
2245:                                    returnTypeTree, Collections
2246:                                            .<TypeParameterTree> emptyList(),
2247:                                    formalArguments, thrown, make.Block(
2248:                                            methodStatements, false), null);
2249:                            TreePath pathToClass = findClass(expression);
2250:
2251:                            assert pathToClass != null;
2252:
2253:                            ClassTree nueClass = GeneratorUtils
2254:                                    .insertClassMember(copy, pathToClass,
2255:                                            method);
2256:
2257:                            copy.rewrite(pathToClass.getLeaf(), nueClass);
2258:                            copy.rewrite(expression.getLeaf(), invocation);
2259:                        }
2260:                    }).commit();
2261:
2262:                    return null;
2263:                }
2264:
2265:            }
2266:
2267:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.