KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > java > hints > CreateElement


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19 package org.netbeans.modules.java.hints;
20
21 import com.sun.source.tree.ArrayAccessTree;
22 import com.sun.source.tree.AssertTree;
23 import com.sun.source.tree.AssignmentTree;
24 import com.sun.source.tree.BinaryTree;
25 import com.sun.source.tree.ClassTree;
26 import com.sun.source.tree.DoWhileLoopTree;
27 import com.sun.source.tree.EnhancedForLoopTree;
28 import com.sun.source.tree.ForLoopTree;
29 import com.sun.source.tree.IfTree;
30 import com.sun.source.tree.InstanceOfTree;
31 import com.sun.source.tree.MemberSelectTree;
32 import com.sun.source.tree.MethodTree;
33 import com.sun.source.tree.ParenthesizedTree;
34 import com.sun.source.tree.ReturnTree;
35 import com.sun.source.tree.SwitchTree;
36 import com.sun.source.tree.SynchronizedTree;
37 import com.sun.source.tree.ThrowTree;
38 import com.sun.source.tree.Tree;
39 import com.sun.source.tree.Tree.Kind;
40 import com.sun.source.tree.UnaryTree;
41 import com.sun.source.tree.VariableTree;
42 import com.sun.source.tree.WhileLoopTree;
43 import com.sun.source.util.TreePath;
44 import java.io.IOException JavaDoc;
45 import java.util.ArrayList JavaDoc;
46 import java.util.Collections JavaDoc;
47 import java.util.EnumSet JavaDoc;
48 import java.util.List JavaDoc;
49 import java.util.Set JavaDoc;
50 import java.util.logging.Level JavaDoc;
51 import java.util.logging.Logger JavaDoc;
52 import javax.lang.model.element.Element;
53 import javax.lang.model.element.ElementKind;
54 import javax.lang.model.element.Modifier;
55 import javax.lang.model.element.ExecutableElement;
56 import javax.lang.model.element.TypeElement;
57 import javax.lang.model.type.ArrayType;
58 import javax.lang.model.type.DeclaredType;
59 import javax.lang.model.type.ExecutableType;
60 import javax.lang.model.type.TypeKind;
61 import javax.lang.model.type.TypeMirror;
62 import org.netbeans.api.java.source.CancellableTask;
63 import org.netbeans.api.java.source.ClasspathInfo;
64 import org.netbeans.api.java.source.CompilationInfo;
65 import org.netbeans.api.java.source.ElementHandle;
66 import org.netbeans.api.java.source.JavaSource;
67 import org.netbeans.api.java.source.JavaSource.Phase;
68 import org.netbeans.api.java.source.SourceUtils;
69 import org.netbeans.api.java.source.TreeMaker;
70 import org.netbeans.api.java.source.TypeMirrorHandle;
71 import org.netbeans.api.java.source.WorkingCopy;
72 import org.netbeans.modules.java.editor.semantic.Utilities;
73 import org.netbeans.modules.java.hints.spi.ErrorRule;
74 import org.netbeans.spi.editor.hints.ChangeInfo;
75 import org.netbeans.spi.editor.hints.Fix;
76 import org.openide.ErrorManager;
77 import org.openide.filesystems.FileObject;
78
79 /**
80  *
81  * @author Jan Lahoda
82  */

83 public final class CreateElement implements ErrorRule<Void JavaDoc> {
84     
85     /** Creates a new instance of CreateElement */
86     public CreateElement() {
87     }
88     
89     public Set JavaDoc<String JavaDoc> getCodes() {
90         return Collections.singleton("compiler.err.cant.resolve.location");
91     }
92     
93     public List JavaDoc<Fix> run(CompilationInfo info, String JavaDoc diagnosticKey, int offset, TreePath treePath, Data<Void JavaDoc> data) {
94         return analyze(info, offset);
95     }
96     
97     static List JavaDoc<Fix> analyze(CompilationInfo info, int offset) {
98         TreePath errorPath = JavaHintsProvider.findUnresolvedElement(info, offset);
99         
100         if (errorPath == null) {
101             return Collections.<Fix>emptyList();
102         }
103         
104         TreePath parent = null;
105         TreePath firstClass = null;
106         TreePath firstMethod = null;
107         TreePath firstInitializer = null;
108         
109         TreePath path = info.getTreeUtilities().pathFor(offset + 1);
110         while(path != null) {
111             if (parent != null && parent.getLeaf() == errorPath.getLeaf())
112                 parent = path;
113             if (path.getLeaf() == errorPath.getLeaf() && parent == null)
114                 parent = path;
115             if (path.getLeaf().getKind() == Kind.CLASS && firstClass == null)
116                 firstClass = path;
117             if (path.getLeaf().getKind() == Kind.METHOD && firstMethod == null && firstClass == null)
118                 firstMethod = path;
119             //static/dynamic initializer:
120
if ( path.getLeaf().getKind() == Kind.BLOCK && path.getParentPath().getLeaf().getKind() == Kind.CLASS
121                 && firstMethod == null && firstClass == null)
122                 firstInitializer = path;
123             path = path.getParentPath();
124         }
125         
126         if (parent == null || parent.getLeaf() == errorPath.getLeaf() || firstClass == null)
127             return Collections.<Fix>emptyList();
128         
129         Element e = info.getTrees().getElement(errorPath);
130         
131         if (e == null) {
132             return Collections.<Fix>emptyList();
133         }
134         
135         Set JavaDoc<Modifier> modifiers = EnumSet.noneOf(Modifier.class);
136         String JavaDoc simpleName = e.getSimpleName().toString();
137         TypeElement source = (TypeElement) info.getTrees().getElement(firstClass);
138         TypeElement target = null;
139         boolean allowLocalVariables = true;
140         
141         if (errorPath.getLeaf().getKind() == Kind.MEMBER_SELECT) {
142             TreePath exp = new TreePath(errorPath, ((MemberSelectTree) errorPath.getLeaf()).getExpression());
143             Element targetElement = info.getTrees().getElement(exp);
144             TypeMirror targetType = info.getTrees().getTypeMirror(exp);
145             
146             if (targetElement != null && targetType != null && targetType.getKind() != TypeKind.ERROR) {
147                 switch (targetElement.getKind()) {
148                     case CLASS:
149                     case INTERFACE:
150                     case ENUM:
151                     case ANNOTATION_TYPE:
152                         //situation like <something>.ClassName.<identifier>,
153
//targetElement representing <something>.ClassName:
154
//the new element needs to be static
155
target = (TypeElement) targetElement;
156                         modifiers.add(Modifier.STATIC);
157                         break;
158                         
159                     case FIELD:
160                     case ENUM_CONSTANT:
161                     case LOCAL_VARIABLE:
162                     case PARAMETER:
163                     case EXCEPTION_PARAMETER:
164                         TypeMirror tm = targetElement.asType();
165                         if (tm.getKind() == TypeKind.DECLARED) {
166                             target = (TypeElement)((DeclaredType)tm).asElement();
167                         }
168                         break;
169                     case METHOD:
170                         Element el = info.getTypes().asElement(((ExecutableElement) targetElement).getReturnType());
171                         
172                         if (el != null && (el.getKind().isClass() || el.getKind().isInterface())) {
173                             target = (TypeElement) el;
174                         }
175                         
176                         break;
177                     case CONSTRUCTOR:
178                         target = (TypeElement) targetElement.getEnclosingElement();
179                         break;
180                     //TODO: type parameter?
181
}
182             }
183             
184             allowLocalVariables = false;
185         } else {
186             if (errorPath.getLeaf().getKind() == Kind.IDENTIFIER) {
187                 target = source;
188                 
189                 if (firstMethod != null) {
190                     if (((MethodTree)firstMethod.getLeaf()).getModifiers().getFlags().contains(Modifier.STATIC)) {
191                         modifiers.add(Modifier.STATIC);
192                     }
193                 } else {
194                     //TODO: outside of any method...
195
}
196             }
197         }
198         
199         if (target == null) {
200             if (JavaHintsProvider.ERR.isLoggable(ErrorManager.INFORMATIONAL)) {
201                 JavaHintsProvider.ERR.log(ErrorManager.INFORMATIONAL, "target=null");
202                 JavaHintsProvider.ERR.log(ErrorManager.INFORMATIONAL, "offset=" + offset);
203                 JavaHintsProvider.ERR.log(ErrorManager.INFORMATIONAL, "errorTree=" + errorPath.getLeaf());
204             }
205             
206             return Collections.<Fix>emptyList();
207         }
208         
209         modifiers.addAll(getAccessModifiers(source, target));
210         
211         List JavaDoc<Fix> result = new ArrayList JavaDoc<Fix>();
212         
213         Set JavaDoc<FixTypes> fixTypes = EnumSet.noneOf(FixTypes.class);
214         List JavaDoc<? extends TypeMirror> types = resolveType(fixTypes, info, parent, errorPath.getLeaf(), offset);
215         
216         if (types == null || types.isEmpty()) {
217             return Collections.<Fix>emptyList();
218         }
219         
220         //XXX: should reasonably consider all the found type candidates, not only the one:
221
TypeMirror type = types.get(0);
222         
223         if (type == null || type.getKind() == TypeKind.VOID) {
224             return Collections.<Fix>emptyList();
225         }
226         
227         //currently, we cannot handle error types, TYPEVARs and WILDCARDs:
228
if (containsErrorsOrTypevarsRecursively(type)) {
229             return Collections.<Fix>emptyList();
230         }
231         
232         if (fixTypes.contains(FixTypes.FIELD)) {
233             result.add(new CreateFieldFix(info, simpleName, modifiers, target, type));
234         }
235         
236         if (allowLocalVariables && (fixTypes.contains(FixTypes.LOCAL) || types.contains(FixTypes.PARAM))) {
237             ExecutableElement ee = null;
238             
239             if (firstMethod != null) {
240                 ee = (ExecutableElement) info.getTrees().getElement(firstMethod);
241             }
242             
243             if ((ee != null) && type != null) {
244                 int identifierPos = (int) info.getTrees().getSourcePositions().getStartPosition(info.getCompilationUnit(), errorPath.getLeaf());
245                 if (ee != null && fixTypes.contains(FixTypes.PARAM))
246                     result.add(new AddParameterOrLocalFix(info, type, simpleName, true, identifierPos));
247                 if (fixTypes.contains(FixTypes.LOCAL))
248                     result.add(new AddParameterOrLocalFix(info, type, simpleName, false, identifierPos));
249             }
250         }
251         
252         return result;
253     }
254     
255     public void cancel() {
256         //XXX: not done yet
257
}
258     
259     public String JavaDoc getId() {
260         return CreateElement.class.getName();
261     }
262     
263     public String JavaDoc getDisplayName() {
264         return "Create Field Fix";
265     }
266     
267     public String JavaDoc getDescription() {
268         return "Create Field Fix";
269     }
270     
271     //XXX: currently we cannot fix:
272
//xxx = new ArrayList<Unknown>();
273
//=>
274
//ArrayList<Unknown> xxx;
275
//xxx = new ArrayList<Unknown>();
276
private static boolean containsErrorsOrTypevarsRecursively(TypeMirror tm) {
277         switch (tm.getKind()) {
278             case WILDCARD:
279             case TYPEVAR:
280             case ERROR:
281                 return true;
282             case DECLARED:
283                 DeclaredType type = (DeclaredType) tm;
284                 
285                 for (TypeMirror t : type.getTypeArguments()) {
286                     if (containsErrorsOrTypevarsRecursively(t))
287                         return true;
288                 }
289                 
290                 return false;
291             case ARRAY:
292                 return containsErrorsOrTypevarsRecursively(((ArrayType) tm).getComponentType());
293             default:
294                 return false;
295         }
296     }
297     
298     private static EnumSet JavaDoc<Modifier> getAccessModifiers(TypeElement source, TypeElement target) {
299         TypeElement outterMostSource = SourceUtils.getOutermostEnclosingTypeElement(source);
300         TypeElement outterMostTarget = SourceUtils.getOutermostEnclosingTypeElement(target);
301         
302         if (outterMostSource.equals(outterMostTarget)) {
303             return EnumSet.of(Modifier.PRIVATE);
304         }
305         
306         Element sourcePackage = outterMostSource.getEnclosingElement();
307         Element targetPackage = outterMostTarget.getEnclosingElement();
308         
309         if (sourcePackage.equals(targetPackage)) {
310             return EnumSet.noneOf(Modifier.class);
311         }
312         
313         //TODO: protected?
314
return EnumSet.of(Modifier.PUBLIC);
315     }
316     
317     private static enum FixTypes {
318         PARAM, LOCAL, FIELD
319     }
320     
321     private static List JavaDoc<? extends TypeMirror> resolveType(Set JavaDoc<FixTypes> types, CompilationInfo info, TreePath currentPath, Tree unresolved, int offset) {
322         switch (currentPath.getLeaf().getKind()) {
323             case METHOD:
324                 return computeMethod(types, info, currentPath, unresolved, offset);
325             case MEMBER_SELECT:
326                 return computeMemberSelect(types, info, currentPath, unresolved, offset);
327             case ASSIGNMENT:
328                 return computeAssignment(types, info, currentPath, unresolved, offset);
329             case ENHANCED_FOR_LOOP:
330                 return computeEnhancedForLoop(types, info, currentPath, unresolved, offset);
331             case ARRAY_ACCESS:
332                 return computeArrayAccess(types, info, currentPath, unresolved, offset);
333             case VARIABLE:
334                 return computeVariableDeclaration(types, info, currentPath, unresolved, offset);
335             case ASSERT:
336                 return computeAssert(types, info, currentPath, unresolved, offset);
337             case PARENTHESIZED:
338                 return computeParenthesis(types, info, currentPath, unresolved, offset);
339             case DO_WHILE_LOOP:
340                 return computePrimitiveType(types, info, ((DoWhileLoopTree) currentPath.getLeaf()).getCondition(), unresolved, TypeKind.BOOLEAN);
341             case FOR_LOOP:
342                 return computePrimitiveType(types, info, ((ForLoopTree) currentPath.getLeaf()).getCondition(), unresolved, TypeKind.BOOLEAN);
343             case IF:
344                 return computePrimitiveType(types, info, ((IfTree) currentPath.getLeaf()).getCondition(), unresolved, TypeKind.BOOLEAN);
345             case WHILE_LOOP:
346                 return computePrimitiveType(types, info, ((WhileLoopTree) currentPath.getLeaf()).getCondition(), unresolved, TypeKind.BOOLEAN);
347             case SYNCHRONIZED:
348                 return computeReferenceType(types, info, ((SynchronizedTree) currentPath.getLeaf()).getExpression(), unresolved, "java.lang.Object");
349             case THROW:
350                 return computeReferenceType(types, info, ((ThrowTree) currentPath.getLeaf()).getExpression(), unresolved, "java.lang.Exception");
351             case INSTANCE_OF:
352                 return computeReferenceType(types, info, ((InstanceOfTree) currentPath.getLeaf()).getExpression(), unresolved, "java.lang.Object");
353             case SWITCH:
354                 //TODO: should consider also values in the cases?:
355
return computePrimitiveType(types, info, ((SwitchTree) currentPath.getLeaf()).getExpression(), unresolved, TypeKind.INT);
356             case RETURN:
357                 return computeReturn(types, info, currentPath, unresolved, offset);
358                 
359             case POSTFIX_INCREMENT:
360             case POSTFIX_DECREMENT:
361             case PREFIX_INCREMENT:
362             case PREFIX_DECREMENT:
363             case UNARY_PLUS:
364             case UNARY_MINUS:
365             case BITWISE_COMPLEMENT:
366             case LOGICAL_COMPLEMENT:
367                 return computeUnary(types, info, currentPath, unresolved, offset);
368
369             case MULTIPLY:
370             case DIVIDE:
371             case REMAINDER:
372             case PLUS:
373             case MINUS:
374             case LEFT_SHIFT:
375             case RIGHT_SHIFT:
376             case UNSIGNED_RIGHT_SHIFT:
377             case LESS_THAN:
378             case GREATER_THAN:
379             case LESS_THAN_EQUAL:
380             case GREATER_THAN_EQUAL:
381             case EQUAL_TO:
382             case NOT_EQUAL_TO:
383             case AND:
384             case XOR:
385             case OR:
386             case CONDITIONAL_AND:
387             case CONDITIONAL_OR:
388                 return computeBinaryOperator(types, info, currentPath, unresolved, offset);
389                 
390             case MULTIPLY_ASSIGNMENT:
391             case DIVIDE_ASSIGNMENT:
392             case REMAINDER_ASSIGNMENT:
393             case PLUS_ASSIGNMENT:
394             case MINUS_ASSIGNMENT:
395             case LEFT_SHIFT_ASSIGNMENT:
396             case RIGHT_SHIFT_ASSIGNMENT:
397             case UNSIGNED_RIGHT_SHIFT_ASSIGNMENT:
398             case AND_ASSIGNMENT:
399             case XOR_ASSIGNMENT:
400             case OR_ASSIGNMENT:
401                 //XXX: return computeCompoundAssignment(types, info, currentPath, unresolved, offset);
402
return null;
403                         
404             case ARRAY_TYPE:
405             case BLOCK:
406             case BREAK:
407             case CATCH:
408             case CLASS:
409             case COMPILATION_UNIT:
410             case CONTINUE:
411             case EXPRESSION_STATEMENT:
412             case IMPORT:
413             case IDENTIFIER:
414             case TYPE_CAST:
415             case PARAMETERIZED_TYPE:
416             case TRY:
417             case EMPTY_STATEMENT:
418             case PRIMITIVE_TYPE:
419             case LABELED_STATEMENT:
420             case MODIFIERS:
421             case ERRONEOUS:
422             case OTHER:
423             case INT_LITERAL:
424             case LONG_LITERAL:
425             case FLOAT_LITERAL:
426             case DOUBLE_LITERAL:
427             case BOOLEAN_LITERAL:
428             case CHAR_LITERAL:
429             case STRING_LITERAL:
430             case NULL_LITERAL:
431             case TYPE_PARAMETER:
432                 //ignored:
433
return null;
434                 
435             case CASE:
436             case ANNOTATION:
437             case CONDITIONAL_EXPRESSION:
438             case NEW_ARRAY:
439             case NEW_CLASS:
440             case UNBOUNDED_WILDCARD:
441             case EXTENDS_WILDCARD:
442             case SUPER_WILDCARD:
443                 //XXX: currently unhandled
444
return null;
445                 
446             default:
447                 //should not happen unless set of Tree.Kind changes:
448
return null;
449         }
450     }
451     
452     private static List JavaDoc<? extends TypeMirror> computeBinaryOperator(Set JavaDoc<FixTypes> types, CompilationInfo info, TreePath parent, Tree error, int offset) {
453         BinaryTree bt = (BinaryTree) parent.getLeaf();
454         TreePath typeToResolve = null;
455         
456         if (bt.getLeftOperand() == error) {
457             typeToResolve = new TreePath(parent, bt.getRightOperand());
458         }
459         
460         if (bt.getRightOperand() == error) {
461             typeToResolve = new TreePath(parent, bt.getLeftOperand());
462         }
463         
464         types.add(FixTypes.PARAM);
465         types.add(FixTypes.LOCAL);
466         types.add(FixTypes.FIELD);
467         
468         return typeToResolve != null ? Collections.singletonList(info.getTrees().getTypeMirror(typeToResolve)) : null;
469     }
470     
471     private static List JavaDoc<? extends TypeMirror> computeMethod(Set JavaDoc<FixTypes> types, CompilationInfo info, TreePath parent, Tree error, int offset) {
472         //class or field:
473
//check the error is in the body:
474
//#92419: check for abstract method/method without body:
475
MethodTree mt = (MethodTree) parent.getLeaf();
476         
477         if (mt.getBody() == null) {
478             return null;
479         }
480         
481         try {
482             int bodyStart = Utilities.findBodyStart(parent.getLeaf(), info.getCompilationUnit(), info.getTrees().getSourcePositions(), info.getDocument());
483             int bodyEnd = (int) info.getTrees().getSourcePositions().getEndPosition(info.getCompilationUnit(), parent.getLeaf());
484             
485             types.add(FixTypes.PARAM);
486             types.add(FixTypes.LOCAL);
487             types.add(FixTypes.FIELD);
488             
489             if (bodyStart <= offset && offset <= bodyEnd)
490                 return Collections.singletonList(info.getElements().getTypeElement("java.lang.Object").asType());
491         } catch (IOException JavaDoc ex) {
492             Logger.getLogger("global").log(Level.INFO, ex.getMessage(), ex);
493         }
494         
495         return null;
496     }
497     
498     private static List JavaDoc<? extends TypeMirror> computeMemberSelect(Set JavaDoc<FixTypes> types, CompilationInfo info, TreePath parent, Tree error, int offset) {
499         //class or field:
500
MemberSelectTree ms = (MemberSelectTree) parent.getLeaf();
501         if (!"class".equals(ms.getIdentifier().toString())) {//we obviously should not propose "Create Field" for unknown.class:
502
types.add(FixTypes.FIELD);
503             return Collections.singletonList(info.getElements().getTypeElement("java.lang.Object").asType());
504         }
505         
506         return null;
507     }
508     
509     private static List JavaDoc<? extends TypeMirror> computeAssignment(Set JavaDoc<FixTypes> types, CompilationInfo info, TreePath parent, Tree error, int offset) {
510         AssignmentTree at = (AssignmentTree) parent.getLeaf();
511         TypeMirror type = null;
512         
513         if (at.getVariable() == error) {
514             type = info.getTrees().getTypeMirror(new TreePath(parent, at.getExpression()));
515             
516             if (type.getKind() == TypeKind.EXECUTABLE) {
517                 //TODO: does not actualy work, attempt to solve situations like:
518
//t = Collections.emptyList()
519
//t = Collections.<String>emptyList();
520
//see also testCreateFieldMethod1 and testCreateFieldMethod2 tests:
521
type = ((ExecutableType) type).getReturnType();
522             }
523         }
524         
525         if (at.getExpression() == error) {
526             type = info.getTrees().getTypeMirror(new TreePath(parent, at.getVariable()));
527         }
528         
529         //class or field:
530
if (type == null) {
531             if (JavaHintsProvider.ERR.isLoggable(ErrorManager.INFORMATIONAL)) {
532                 JavaHintsProvider.ERR.log(ErrorManager.INFORMATIONAL, "offset=" + offset);
533                 JavaHintsProvider.ERR.log(ErrorManager.INFORMATIONAL, "errorTree=" + error);
534                 JavaHintsProvider.ERR.log(ErrorManager.INFORMATIONAL, "type=null");
535             }
536             
537             return null;
538         }
539         
540         types.add(FixTypes.PARAM);
541         types.add(FixTypes.LOCAL);
542         types.add(FixTypes.FIELD);
543         
544         return Collections.singletonList(type);
545     }
546     
547     private static List JavaDoc<? extends TypeMirror> computeEnhancedForLoop(Set JavaDoc<FixTypes> types, CompilationInfo info, TreePath parent, Tree error, int offset) {
548         EnhancedForLoopTree efl = (EnhancedForLoopTree) parent.getLeaf();
549         
550         if (efl.getExpression() != error) {
551             return null;
552         }
553         
554         types.add(FixTypes.PARAM);
555         types.add(FixTypes.LOCAL);
556         types.add(FixTypes.FIELD);
557         
558         TypeElement iterable = info.getElements().getTypeElement("java.lang.Iterable");
559         TypeMirror argument = info.getTrees().getTypeMirror(new TreePath(new TreePath(parent, efl.getVariable()), efl.getVariable().getType()));
560         
561         return Collections.singletonList(info.getTypes().getDeclaredType(iterable, argument));
562     }
563     
564     private static List JavaDoc<? extends TypeMirror> computeArrayAccess(Set JavaDoc<FixTypes> types, CompilationInfo info, TreePath parent, Tree error, int offset) {
565         ArrayAccessTree aat = (ArrayAccessTree) parent.getLeaf();
566         
567         if (aat.getExpression() == error) {
568             TreePath parentParent = parent.getParentPath();
569             List JavaDoc<? extends TypeMirror> upperTypes = resolveType(types, info, parentParent, aat, offset);
570             
571             if (upperTypes == null) {
572                 return null;
573             }
574             
575             List JavaDoc<TypeMirror> arrayTypes = new ArrayList JavaDoc<TypeMirror>();
576             
577             for (TypeMirror tm : upperTypes) {
578                 arrayTypes.add(info.getTypes().getArrayType(tm));
579             }
580             
581             return arrayTypes;
582         }
583         
584         if (aat.getIndex() == error) {
585             types.add(FixTypes.PARAM);
586             types.add(FixTypes.LOCAL);
587             types.add(FixTypes.FIELD);
588             
589             return Collections.singletonList(info.getTypes().getPrimitiveType(TypeKind.INT));
590         }
591         
592         return null;
593     }
594     
595     private static List JavaDoc<? extends TypeMirror> computeVariableDeclaration(Set JavaDoc<FixTypes> types, CompilationInfo info, TreePath parent, Tree error, int offset) {
596         VariableTree vt = (VariableTree) parent.getLeaf();
597         
598         if (vt.getInitializer() != error) {
599             return null;
600         }
601         
602         types.add(FixTypes.PARAM);
603         types.add(FixTypes.LOCAL);
604         types.add(FixTypes.FIELD);
605         
606         return Collections.singletonList(info.getTrees().getTypeMirror(new TreePath(parent, vt.getType())));
607     }
608     
609     private static List JavaDoc<? extends TypeMirror> computeAssert(Set JavaDoc<FixTypes> types, CompilationInfo info, TreePath parent, Tree error, int offset) {
610         AssertTree at = (AssertTree) parent.getLeaf();
611         
612         types.add(FixTypes.PARAM);
613         types.add(FixTypes.LOCAL);
614         types.add(FixTypes.FIELD);
615         
616         if (at.getCondition() == error) {
617             return Collections.singletonList(info.getTypes().getPrimitiveType(TypeKind.BOOLEAN));
618         }
619         
620         if (at.getDetail() == error) {
621             return Collections.singletonList(info.getElements().getTypeElement("java.lang.Object").asType());
622         }
623         
624         
625         return null;
626     }
627     
628     private static List JavaDoc<? extends TypeMirror> computeParenthesis(Set JavaDoc<FixTypes> types, CompilationInfo info, TreePath parent, Tree error, int offset) {
629         ParenthesizedTree pt = (ParenthesizedTree) parent.getLeaf();
630         
631         if (pt.getExpression() != error) {
632             return null;
633         }
634         
635         TreePath parentParent = parent.getParentPath();
636         List JavaDoc<? extends TypeMirror> upperTypes = resolveType(types, info, parentParent, pt, offset);
637         
638         if (upperTypes == null) {
639             return null;
640         }
641         
642         return upperTypes;
643     }
644     
645     private static List JavaDoc<? extends TypeMirror> computePrimitiveType(Set JavaDoc<FixTypes> types, CompilationInfo info, Tree expression, Tree error, TypeKind kind) {
646         if (expression == error) {
647             types.add(FixTypes.PARAM);
648             types.add(FixTypes.LOCAL);
649             types.add(FixTypes.FIELD);
650             
651             return Collections.singletonList(info.getTypes().getPrimitiveType(kind));
652         }
653         
654         return null;
655     }
656     
657     private static List JavaDoc<? extends TypeMirror> computeReferenceType(Set JavaDoc<FixTypes> types, CompilationInfo info, Tree expression, Tree error, String JavaDoc type) {
658         if (expression == error) {
659             types.add(FixTypes.PARAM);
660             types.add(FixTypes.LOCAL);
661             types.add(FixTypes.FIELD);
662             
663             return Collections.singletonList(info.getElements().getTypeElement(type).asType());
664         }
665         
666         return null;
667     }
668     
669     private static List JavaDoc<? extends TypeMirror> computeUnary(Set JavaDoc<FixTypes> types, CompilationInfo info, TreePath parent, Tree error, int offset) {
670         UnaryTree tree = (UnaryTree) parent.getLeaf();
671         
672         if (tree.getExpression() == error) {
673             List JavaDoc<? extends TypeMirror> parentTypes = resolveType(types, info, parent.getParentPath(), tree, offset);
674             
675             if (parentTypes == null) {
676                 types.add(FixTypes.PARAM);
677                 types.add(FixTypes.LOCAL);
678                 types.add(FixTypes.FIELD);
679                 
680                 return Collections.singletonList(info.getTypes().getPrimitiveType(TypeKind.INT));
681             }
682             
683             return parentTypes;
684         }
685         
686         return null;
687     }
688     
689     private static List JavaDoc<? extends TypeMirror> computeReturn(Set JavaDoc<FixTypes> types, CompilationInfo info, TreePath parent, Tree error, int offset) {
690         ReturnTree rt = (ReturnTree) parent.getLeaf();
691         
692         if (rt.getExpression() == error) {
693             TreePath method = findMethod(parent);
694             
695             if (method == null) {
696                 return null;
697             }
698             
699             Element el = info.getTrees().getElement(method);
700             
701             if (el == null || el.getKind() != ElementKind.METHOD) {
702                 return null;
703             }
704             
705             types.add(FixTypes.PARAM);
706             types.add(FixTypes.LOCAL);
707             types.add(FixTypes.FIELD);
708             
709             return Collections.singletonList(((ExecutableElement) el).getReturnType());
710         }
711         
712         return null;
713     }
714     
715     private static final Set JavaDoc<Kind> STOP_LOOKING_FOR_METHOD = EnumSet.of(Kind.METHOD, Kind.CLASS, Kind.COMPILATION_UNIT);
716             
717     private static TreePath findMethod(TreePath tp) {
718         while (!STOP_LOOKING_FOR_METHOD.contains(tp.getLeaf().getKind())) {
719             tp = tp.getParentPath();
720         }
721         
722         if (tp.getLeaf().getKind() == Kind.METHOD) {
723             return tp;
724         }
725         
726         return null;
727     }
728     
729     static final class CreateFieldFix implements Fix {
730         
731         private FileObject targetFile;
732         private ElementHandle<TypeElement> target;
733         private TypeMirrorHandle proposedType;
734         private ClasspathInfo cpInfo;
735         private Set JavaDoc<Modifier> modifiers;
736         
737         private String JavaDoc name;
738         private String JavaDoc inFQN;
739         
740         public CreateFieldFix(CompilationInfo info, String JavaDoc name, Set JavaDoc<Modifier> modifiers, TypeElement target, TypeMirror proposedType) {
741             this.name = name;
742             this.inFQN = target.getQualifiedName().toString();
743             this.cpInfo = info.getClasspathInfo();
744             this.modifiers = modifiers;
745             this.targetFile = SourceUtils.getFile(target, cpInfo);
746             this.target = ElementHandle.create(target);
747             if (proposedType.getKind() == TypeKind.NULL) {
748                 proposedType = info.getElements().getTypeElement("java.lang.Object").asType();
749             }
750             this.proposedType = TypeMirrorHandle.create(proposedType);
751         }
752         
753         public String JavaDoc getText() {
754             return "Create field " + name + " in " + inFQN;
755         }
756         
757         public ChangeInfo implement() {
758             try {
759                 //use the original cp-info so it is "sure" that the proposedType can be resolved:
760
JavaSource js = JavaSource.create(cpInfo, targetFile);
761                 
762                 js.runModificationTask(new CancellableTask<WorkingCopy>() {
763                     public void cancel() {
764                     }
765                     public void run(final WorkingCopy working) throws IOException JavaDoc {
766                         working.toPhase(Phase.RESOLVED);
767                         TypeElement targetType = target.resolve(working);
768                         
769                         if (targetType == null) {
770                             JavaHintsProvider.LOG.log(Level.INFO, "Cannot resolve target.");
771                             return;
772                         }
773                         
774                         ClassTree targetTree = working.getTrees().getTree(targetType);
775                         
776                         if (targetTree == null) {
777                             JavaHintsProvider.LOG.log(Level.INFO, "Cannot resolve target tree: " + targetType.getQualifiedName() + ".");
778                             return;
779                         }
780                         
781                         TypeMirror proposedType = CreateFieldFix.this.proposedType.resolve(working);
782                         
783                         if (proposedType == null) {
784                             JavaHintsProvider.LOG.log(Level.INFO, "Cannot resolve proposed type.");
785                             return;
786                         }
787                         
788                         TreeMaker make = working.getTreeMaker();
789                         TypeMirror tm = proposedType;
790                         VariableTree var = null;
791                         
792                         if (tm.getKind() == TypeKind.DECLARED || tm.getKind() == TypeKind.ARRAY) {
793                             var = make.Variable(make.Modifiers(modifiers), name, make.Type(tm), null);
794                         }
795                         
796                         if (tm.getKind().isPrimitive()) {
797                             var = make.Variable(make.Modifiers(modifiers), name, make.Type(tm), null);
798                         }
799                         
800                         assert var != null : tm.getKind();
801                         ClassTree decl = make.addClassMember(targetTree, var);
802                         working.rewrite(targetTree, decl);
803                     }
804                 }).commit();
805             } catch (IOException JavaDoc e) {
806                 throw (IllegalStateException JavaDoc) new IllegalStateException JavaDoc().initCause(e);
807             }
808             
809             return null;
810         }
811         
812         String JavaDoc toDebugString(CompilationInfo info) {
813             return "CreateFieldFix:" + name + ":" + target.getQualifiedName() + ":" + proposedType.resolve(info).toString() + ":" + modifiers;
814         }
815     }
816     
817 }
818
Popular Tags