001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.modules.java.hints.errors;
042:
043: import com.sun.source.tree.ArrayAccessTree;
044: import com.sun.source.tree.AssertTree;
045: import com.sun.source.tree.AssignmentTree;
046: import com.sun.source.tree.BinaryTree;
047: import com.sun.source.tree.ClassTree;
048: import com.sun.source.tree.ConditionalExpressionTree;
049: import com.sun.source.tree.DoWhileLoopTree;
050: import com.sun.source.tree.EnhancedForLoopTree;
051: import com.sun.source.tree.ForLoopTree;
052: import com.sun.source.tree.IfTree;
053: import com.sun.source.tree.InstanceOfTree;
054: import com.sun.source.tree.MemberSelectTree;
055: import com.sun.source.tree.MethodInvocationTree;
056: import com.sun.source.tree.MethodTree;
057: import com.sun.source.tree.NewArrayTree;
058: import com.sun.source.tree.NewClassTree;
059: import com.sun.source.tree.ParameterizedTypeTree;
060: import com.sun.source.tree.ParenthesizedTree;
061: import com.sun.source.tree.ReturnTree;
062: import com.sun.source.tree.SwitchTree;
063: import com.sun.source.tree.SynchronizedTree;
064: import com.sun.source.tree.ThrowTree;
065: import com.sun.source.tree.Tree;
066: import com.sun.source.tree.Tree.Kind;
067: import com.sun.source.tree.TypeParameterTree;
068: import com.sun.source.tree.UnaryTree;
069: import com.sun.source.tree.VariableTree;
070: import com.sun.source.tree.WhileLoopTree;
071: import com.sun.source.util.TreePath;
072: import java.io.IOException;
073: import java.util.ArrayList;
074: import java.util.Collections;
075: import java.util.EnumSet;
076: import java.util.List;
077: import java.util.Set;
078: import java.util.logging.Level;
079: import java.util.logging.Logger;
080: import javax.lang.model.element.Element;
081: import javax.lang.model.element.ElementKind;
082: import javax.lang.model.element.ExecutableElement;
083: import javax.lang.model.element.TypeElement;
084: import javax.lang.model.type.ArrayType;
085: import javax.lang.model.type.DeclaredType;
086: import javax.lang.model.type.ExecutableType;
087: import javax.lang.model.type.TypeKind;
088: import javax.lang.model.type.TypeMirror;
089: import javax.lang.model.type.TypeVariable;
090: import javax.lang.model.util.Types;
091: import javax.swing.text.Document;
092: import org.netbeans.api.java.source.CompilationInfo;
093: import org.netbeans.modules.java.editor.semantic.Utilities;
094: import org.netbeans.modules.java.hints.infrastructure.ErrorHintsProvider;
095: import org.openide.ErrorManager;
096:
097: /**
098: *
099: * @author Jan Lahoda
100: */
101: public final class CreateElementUtilities {
102:
103: private CreateElementUtilities() {
104: }
105:
106: public static List<? extends TypeMirror> resolveType(
107: Set<ElementKind> types, CompilationInfo info,
108: TreePath currentPath, Tree unresolved, int offset,
109: TypeMirror[] typeParameterBound, int[] numTypeParameters) {
110: switch (currentPath.getLeaf().getKind()) {
111: case METHOD:
112: return computeMethod(types, info, currentPath,
113: typeParameterBound, unresolved, offset);
114: case MEMBER_SELECT:
115: return computeMemberSelect(types, info, currentPath,
116: unresolved, offset);
117: case ASSIGNMENT:
118: return computeAssignment(types, info, currentPath,
119: unresolved, offset);
120: case ENHANCED_FOR_LOOP:
121: return computeEnhancedForLoop(types, info, currentPath,
122: unresolved, offset);
123: case ARRAY_ACCESS:
124: return computeArrayAccess(types, info, currentPath,
125: unresolved, offset);
126: case VARIABLE:
127: return computeVariableDeclaration(types, info, currentPath,
128: unresolved, offset);
129: case ASSERT:
130: return computeAssert(types, info, currentPath, unresolved,
131: offset);
132: case PARENTHESIZED:
133: return computeParenthesis(types, info, currentPath,
134: unresolved, offset);
135: case DO_WHILE_LOOP:
136: return computePrimitiveType(types, info,
137: ((DoWhileLoopTree) currentPath.getLeaf())
138: .getCondition(), unresolved,
139: TypeKind.BOOLEAN);
140: case FOR_LOOP:
141: return computePrimitiveType(types, info,
142: ((ForLoopTree) currentPath.getLeaf())
143: .getCondition(), unresolved,
144: TypeKind.BOOLEAN);
145: case IF:
146: return computePrimitiveType(types, info,
147: ((IfTree) currentPath.getLeaf()).getCondition(),
148: unresolved, TypeKind.BOOLEAN);
149: case WHILE_LOOP:
150: return computePrimitiveType(types, info,
151: ((WhileLoopTree) currentPath.getLeaf())
152: .getCondition(), unresolved,
153: TypeKind.BOOLEAN);
154: case SYNCHRONIZED:
155: return computeReferenceType(types, info,
156: ((SynchronizedTree) currentPath.getLeaf())
157: .getExpression(), unresolved,
158: "java.lang.Object");
159: case THROW:
160: return computeReferenceType(
161: types,
162: info,
163: ((ThrowTree) currentPath.getLeaf()).getExpression(),
164: unresolved, "java.lang.Exception");
165: case INSTANCE_OF:
166: return computeReferenceType(types, info,
167: ((InstanceOfTree) currentPath.getLeaf())
168: .getExpression(), unresolved,
169: "java.lang.Object");
170: case SWITCH:
171: //TODO: should consider also values in the cases?:
172: return computePrimitiveType(types, info,
173: ((SwitchTree) currentPath.getLeaf())
174: .getExpression(), unresolved, TypeKind.INT);
175: case EXPRESSION_STATEMENT:
176: return Collections.singletonList(info.getTypes().getNoType(
177: TypeKind.VOID));
178:
179: case RETURN:
180: return computeReturn(types, info, currentPath, unresolved,
181: offset);
182: case TYPE_PARAMETER:
183: return computeTypeParameter(types, info, currentPath,
184: unresolved, offset);
185: case PARAMETERIZED_TYPE:
186: return computeParametrizedType(types, info, currentPath,
187: unresolved, offset, typeParameterBound,
188: numTypeParameters);
189: case CLASS:
190: return computeClass(types, info, currentPath, unresolved,
191: offset);
192:
193: case CONDITIONAL_EXPRESSION:
194: return computeConditionalExpression(types, info,
195: currentPath, unresolved, offset);
196:
197: case NEW_ARRAY:
198: return computeNewArray(types, info, currentPath,
199: unresolved, offset);
200:
201: case METHOD_INVOCATION:
202: return computeMethodInvocation(types, info, currentPath,
203: unresolved, offset);
204:
205: case NEW_CLASS:
206: return computeNewClass(types, info, currentPath,
207: unresolved, offset);
208:
209: case POSTFIX_INCREMENT:
210: case POSTFIX_DECREMENT:
211: case PREFIX_INCREMENT:
212: case PREFIX_DECREMENT:
213: case UNARY_PLUS:
214: case UNARY_MINUS:
215: case BITWISE_COMPLEMENT:
216: case LOGICAL_COMPLEMENT:
217: return computeUnary(types, info, currentPath, unresolved,
218: offset);
219:
220: case MULTIPLY:
221: case DIVIDE:
222: case REMAINDER:
223: case PLUS:
224: case MINUS:
225: case LEFT_SHIFT:
226: case RIGHT_SHIFT:
227: case UNSIGNED_RIGHT_SHIFT:
228: case LESS_THAN:
229: case GREATER_THAN:
230: case LESS_THAN_EQUAL:
231: case GREATER_THAN_EQUAL:
232: case EQUAL_TO:
233: case NOT_EQUAL_TO:
234: case AND:
235: case XOR:
236: case OR:
237: case CONDITIONAL_AND:
238: case CONDITIONAL_OR:
239: return computeBinaryOperator(types, info, currentPath,
240: unresolved, offset);
241:
242: case MULTIPLY_ASSIGNMENT:
243: case DIVIDE_ASSIGNMENT:
244: case REMAINDER_ASSIGNMENT:
245: case PLUS_ASSIGNMENT:
246: case MINUS_ASSIGNMENT:
247: case LEFT_SHIFT_ASSIGNMENT:
248: case RIGHT_SHIFT_ASSIGNMENT:
249: case UNSIGNED_RIGHT_SHIFT_ASSIGNMENT:
250: case AND_ASSIGNMENT:
251: case XOR_ASSIGNMENT:
252: case OR_ASSIGNMENT:
253: //XXX: return computeCompoundAssignment(types, info, currentPath, unresolved, offset);
254: return null;
255:
256: case ARRAY_TYPE:
257: case BLOCK:
258: case BREAK:
259: case CATCH:
260: case COMPILATION_UNIT:
261: case CONTINUE:
262: case IMPORT:
263: case IDENTIFIER:
264: case TYPE_CAST:
265: case TRY:
266: case EMPTY_STATEMENT:
267: case PRIMITIVE_TYPE:
268: case LABELED_STATEMENT:
269: case MODIFIERS:
270: case ERRONEOUS:
271: case OTHER:
272: case INT_LITERAL:
273: case LONG_LITERAL:
274: case FLOAT_LITERAL:
275: case DOUBLE_LITERAL:
276: case BOOLEAN_LITERAL:
277: case CHAR_LITERAL:
278: case STRING_LITERAL:
279: case NULL_LITERAL:
280: //ignored:
281: return null;
282:
283: case CASE:
284: case ANNOTATION:
285: case UNBOUNDED_WILDCARD:
286: case EXTENDS_WILDCARD:
287: case SUPER_WILDCARD:
288: //XXX: currently unhandled
289: return null;
290:
291: default:
292: //should not happen unless set of Tree.Kind changes:
293: return null;
294: }
295: }
296:
297: private static List<? extends TypeMirror> computeBinaryOperator(
298: Set<ElementKind> types, CompilationInfo info,
299: TreePath parent, Tree error, int offset) {
300: BinaryTree bt = (BinaryTree) parent.getLeaf();
301: TreePath typeToResolve = null;
302:
303: if (bt.getLeftOperand() == error) {
304: typeToResolve = new TreePath(parent, bt.getRightOperand());
305: }
306:
307: if (bt.getRightOperand() == error) {
308: typeToResolve = new TreePath(parent, bt.getLeftOperand());
309: }
310:
311: types.add(ElementKind.PARAMETER);
312: types.add(ElementKind.LOCAL_VARIABLE);
313: types.add(ElementKind.FIELD);
314:
315: return typeToResolve != null ? Collections.singletonList(info
316: .getTrees().getTypeMirror(typeToResolve)) : null;
317: }
318:
319: private static List<? extends TypeMirror> computeMethod(
320: Set<ElementKind> types, CompilationInfo info,
321: TreePath parent, TypeMirror[] typeParameterBound,
322: Tree error, int offset) {
323: //class or field:
324: //check the error is in the body:
325: //#92419: check for abstract method/method without body:
326: MethodTree mt = (MethodTree) parent.getLeaf();
327:
328: if (mt.getReturnType() == error) {
329: types.add(ElementKind.CLASS);
330: types.add(ElementKind.INTERFACE);
331: types.add(ElementKind.ENUM);
332: }
333:
334: if (mt.getThrows() != null && !mt.getThrows().isEmpty()
335: && mt.getThrows().get(0) == error) {
336: types.add(ElementKind.CLASS);
337: typeParameterBound[0] = info.getElements().getTypeElement(
338: "java.lang.Exception").asType();
339: }
340:
341: if (mt.getBody() == null) {
342: return null;
343: }
344:
345: try {
346: Document doc = info.getDocument();
347:
348: if (doc != null) {//XXX
349: int bodyStart = Utilities.findBodyStart(parent
350: .getLeaf(), info.getCompilationUnit(), info
351: .getTrees().getSourcePositions(), doc);
352: int bodyEnd = (int) info.getTrees()
353: .getSourcePositions().getEndPosition(
354: info.getCompilationUnit(),
355: parent.getLeaf());
356:
357: types.add(ElementKind.PARAMETER);
358: types.add(ElementKind.LOCAL_VARIABLE);
359: types.add(ElementKind.FIELD);
360:
361: if (bodyStart <= offset && offset <= bodyEnd)
362: return Collections.singletonList(info.getElements()
363: .getTypeElement("java.lang.Object")
364: .asType());
365: }
366: } catch (IOException ex) {
367: Logger.getLogger("global").log(Level.INFO, ex.getMessage(),
368: ex);
369: }
370:
371: return null;
372: }
373:
374: private static List<? extends TypeMirror> computeMemberSelect(
375: Set<ElementKind> types, CompilationInfo info,
376: TreePath parent, Tree error, int offset) {
377: //class or field:
378: MemberSelectTree ms = (MemberSelectTree) parent.getLeaf();
379: final TypeElement jlObject = info.getElements().getTypeElement(
380: "java.lang.Object");
381:
382: if (jlObject != null //may happen if the platform is broken
383: && !"class".equals(ms.getIdentifier().toString())) {//we obviously should not propose "Create Field" for unknown.class:
384: types.add(ElementKind.FIELD);
385: types.add(ElementKind.CLASS);
386: return Collections.singletonList(jlObject.asType());
387: }
388:
389: return null;
390: }
391:
392: private static List<? extends TypeMirror> computeAssignment(
393: Set<ElementKind> types, CompilationInfo info,
394: TreePath parent, Tree error, int offset) {
395: AssignmentTree at = (AssignmentTree) parent.getLeaf();
396: TypeMirror type = null;
397:
398: if (at.getVariable() == error) {
399: type = info.getTrees().getTypeMirror(
400: new TreePath(parent, at.getExpression()));
401:
402: //anonymous class?
403: Set<ElementKind> fm = EnumSet.of(ElementKind.METHOD,
404: ElementKind.FIELD);
405: if (type instanceof DeclaredType) {
406: Element el = ((DeclaredType) type).asElement();
407: if (el.getSimpleName().length() == 0
408: || fm.contains(el.getEnclosingElement()
409: .getKind())) {
410: List<? extends TypeMirror> interfaces = ((TypeElement) el)
411: .getInterfaces();
412: if (interfaces.isEmpty())
413: type = ((TypeElement) el).getSuperclass();
414: else
415: type = interfaces.get(0);
416: }
417: }
418:
419: if (type.getKind() == TypeKind.EXECUTABLE) {
420: //TODO: does not actualy work, attempt to solve situations like:
421: //t = Collections.emptyList()
422: //t = Collections.<String>emptyList();
423: //see also testCreateFieldMethod1 and testCreateFieldMethod2 tests:
424: type = ((ExecutableType) type).getReturnType();
425: }
426: }
427:
428: if (at.getExpression() == error) {
429: type = info.getTrees().getTypeMirror(
430: new TreePath(parent, at.getVariable()));
431: }
432:
433: //class or field:
434: if (type == null) {
435: if (ErrorHintsProvider.ERR
436: .isLoggable(ErrorManager.INFORMATIONAL)) {
437: ErrorHintsProvider.ERR.log(ErrorManager.INFORMATIONAL,
438: "offset=" + offset);
439: ErrorHintsProvider.ERR.log(ErrorManager.INFORMATIONAL,
440: "errorTree=" + error);
441: ErrorHintsProvider.ERR.log(ErrorManager.INFORMATIONAL,
442: "type=null");
443: }
444:
445: return null;
446: }
447:
448: types.add(ElementKind.PARAMETER);
449: types.add(ElementKind.LOCAL_VARIABLE);
450: types.add(ElementKind.FIELD);
451:
452: return Collections.singletonList(type);
453: }
454:
455: private static List<? extends TypeMirror> computeEnhancedForLoop(
456: Set<ElementKind> types, CompilationInfo info,
457: TreePath parent, Tree error, int offset) {
458: EnhancedForLoopTree efl = (EnhancedForLoopTree) parent
459: .getLeaf();
460:
461: if (efl.getExpression() != error) {
462: return null;
463: }
464:
465: TypeMirror argument = info.getTrees().getTypeMirror(
466: new TreePath(new TreePath(parent, efl.getVariable()),
467: efl.getVariable().getType()));
468:
469: if (argument == null)
470: return null;
471:
472: if (argument.getKind().isPrimitive()) {
473: types.add(ElementKind.PARAMETER);
474: types.add(ElementKind.LOCAL_VARIABLE);
475: types.add(ElementKind.FIELD);
476:
477: return Collections.singletonList(info.getTypes()
478: .getArrayType(argument));
479: }
480:
481: TypeElement iterable = info.getElements().getTypeElement(
482: "java.lang.Iterable"); //NOI18N
483: if (iterable == null) {
484: return null;
485: }
486:
487: types.add(ElementKind.PARAMETER);
488: types.add(ElementKind.LOCAL_VARIABLE);
489: types.add(ElementKind.FIELD);
490:
491: return Collections.singletonList(info.getTypes()
492: .getDeclaredType(iterable, argument));
493: }
494:
495: private static List<? extends TypeMirror> computeArrayAccess(
496: Set<ElementKind> types, CompilationInfo info,
497: TreePath parent, Tree error, int offset) {
498: ArrayAccessTree aat = (ArrayAccessTree) parent.getLeaf();
499:
500: if (aat.getExpression() == error) {
501: TreePath parentParent = parent.getParentPath();
502: List<? extends TypeMirror> upperTypes = resolveType(types,
503: info, parentParent, aat, offset, null, null);
504:
505: if (upperTypes == null) {
506: return null;
507: }
508:
509: List<TypeMirror> arrayTypes = new ArrayList<TypeMirror>();
510:
511: for (TypeMirror tm : upperTypes) {
512: if (tm == null)
513: continue;
514: switch (tm.getKind()) {
515: case VOID:
516: case EXECUTABLE:
517: case WILDCARD:
518: case PACKAGE:
519: continue;
520: }
521:
522: arrayTypes.add(info.getTypes().getArrayType(tm));
523: }
524:
525: if (arrayTypes.isEmpty())
526: return null;
527:
528: return arrayTypes;
529: }
530:
531: if (aat.getIndex() == error) {
532: types.add(ElementKind.PARAMETER);
533: types.add(ElementKind.LOCAL_VARIABLE);
534: types.add(ElementKind.FIELD);
535:
536: return Collections.singletonList(info.getTypes()
537: .getPrimitiveType(TypeKind.INT));
538: }
539:
540: return null;
541: }
542:
543: private static List<? extends TypeMirror> computeVariableDeclaration(
544: Set<ElementKind> types, CompilationInfo info,
545: TreePath parent, Tree error, int offset) {
546: VariableTree vt = (VariableTree) parent.getLeaf();
547:
548: if (vt.getInitializer() == error) {
549: types.add(ElementKind.PARAMETER);
550: types.add(ElementKind.LOCAL_VARIABLE);
551: types.add(ElementKind.FIELD);
552:
553: return Collections.singletonList(info.getTrees()
554: .getTypeMirror(new TreePath(parent, vt.getType())));
555: }
556:
557: if (vt.getType() == error) {
558: types.add(ElementKind.CLASS);
559: return Collections.<TypeMirror> emptyList();
560: }
561:
562: return null;
563: }
564:
565: private static List<? extends TypeMirror> computeAssert(
566: Set<ElementKind> types, CompilationInfo info,
567: TreePath parent, Tree error, int offset) {
568: AssertTree at = (AssertTree) parent.getLeaf();
569:
570: types.add(ElementKind.PARAMETER);
571: types.add(ElementKind.LOCAL_VARIABLE);
572: types.add(ElementKind.FIELD);
573:
574: if (at.getCondition() == error) {
575: return Collections.singletonList(info.getTypes()
576: .getPrimitiveType(TypeKind.BOOLEAN));
577: }
578:
579: if (at.getDetail() == error) {
580: return Collections.singletonList(info.getElements()
581: .getTypeElement("java.lang.Object").asType());
582: }
583:
584: return null;
585: }
586:
587: private static List<? extends TypeMirror> computeParenthesis(
588: Set<ElementKind> types, CompilationInfo info,
589: TreePath parent, Tree error, int offset) {
590: ParenthesizedTree pt = (ParenthesizedTree) parent.getLeaf();
591:
592: if (pt.getExpression() != error) {
593: return null;
594: }
595:
596: TreePath parentParent = parent.getParentPath();
597: List<? extends TypeMirror> upperTypes = resolveType(types,
598: info, parentParent, pt, offset, null, null);
599:
600: if (upperTypes == null) {
601: return null;
602: }
603:
604: return upperTypes;
605: }
606:
607: private static List<? extends TypeMirror> computeConditionalExpression(
608: Set<ElementKind> types, CompilationInfo info,
609: TreePath parent, Tree error, int offset) {
610: ConditionalExpressionTree cet = (ConditionalExpressionTree) parent
611: .getLeaf();
612:
613: if (cet.getCondition() == error) {
614: types.add(ElementKind.PARAMETER);
615: types.add(ElementKind.LOCAL_VARIABLE);
616: types.add(ElementKind.FIELD);
617:
618: return Collections.singletonList(info.getTypes()
619: .getPrimitiveType(TypeKind.BOOLEAN));
620: }
621:
622: if (cet.getTrueExpression() == error
623: || cet.getFalseExpression() == error) {
624: types.add(ElementKind.PARAMETER);
625: types.add(ElementKind.LOCAL_VARIABLE);
626: types.add(ElementKind.FIELD);
627:
628: return resolveType(types, info, parent.getParentPath(),
629: cet, offset, null, null);
630: }
631:
632: return null;
633: }
634:
635: private static List<? extends TypeMirror> computePrimitiveType(
636: Set<ElementKind> types, CompilationInfo info,
637: Tree expression, Tree error, TypeKind kind) {
638: if (expression == error) {
639: types.add(ElementKind.PARAMETER);
640: types.add(ElementKind.LOCAL_VARIABLE);
641: types.add(ElementKind.FIELD);
642:
643: return Collections.singletonList(info.getTypes()
644: .getPrimitiveType(kind));
645: }
646:
647: return null;
648: }
649:
650: private static List<? extends TypeMirror> computeReferenceType(
651: Set<ElementKind> types, CompilationInfo info,
652: Tree expression, Tree error, String type) {
653: if (expression == error) {
654: types.add(ElementKind.PARAMETER);
655: types.add(ElementKind.LOCAL_VARIABLE);
656: types.add(ElementKind.FIELD);
657:
658: return Collections.singletonList(info.getElements()
659: .getTypeElement(type).asType());
660: }
661:
662: return null;
663: }
664:
665: private static List<? extends TypeMirror> computeUnary(
666: Set<ElementKind> types, CompilationInfo info,
667: TreePath parent, Tree error, int offset) {
668: UnaryTree tree = (UnaryTree) parent.getLeaf();
669:
670: if (tree.getExpression() == error) {
671: List<? extends TypeMirror> parentTypes = resolveType(types,
672: info, parent.getParentPath(), tree, offset, null,
673: null);
674:
675: if (parentTypes != null) {
676: //may contain only "void", ignore:
677: if (parentTypes.size() != 1) {
678: return parentTypes;
679: }
680: if (parentTypes.get(0).getKind() != TypeKind.VOID) {
681: return parentTypes;
682: }
683: }
684:
685: types.add(ElementKind.PARAMETER);
686: types.add(ElementKind.LOCAL_VARIABLE);
687: types.add(ElementKind.FIELD);
688:
689: return Collections.singletonList(info.getTypes()
690: .getPrimitiveType(TypeKind.INT));
691: }
692:
693: return null;
694: }
695:
696: private static List<? extends TypeMirror> computeReturn(
697: Set<ElementKind> types, CompilationInfo info,
698: TreePath parent, Tree error, int offset) {
699: ReturnTree rt = (ReturnTree) parent.getLeaf();
700:
701: if (rt.getExpression() == error) {
702: TreePath method = findMethod(parent);
703:
704: if (method == null) {
705: return null;
706: }
707:
708: Element el = info.getTrees().getElement(method);
709:
710: if (el == null || el.getKind() != ElementKind.METHOD) {
711: return null;
712: }
713:
714: types.add(ElementKind.PARAMETER);
715: types.add(ElementKind.LOCAL_VARIABLE);
716: types.add(ElementKind.FIELD);
717:
718: return Collections.singletonList(((ExecutableElement) el)
719: .getReturnType());
720: }
721:
722: return null;
723: }
724:
725: private static List<? extends TypeMirror> computeTypeParameter(
726: Set<ElementKind> types, CompilationInfo info,
727: TreePath parent, Tree error, int offset) {
728: TypeParameterTree tpt = (TypeParameterTree) parent.getLeaf();
729:
730: for (Tree t : tpt.getBounds()) {
731: if (t == error) {
732: types.add(ElementKind.CLASS); //XXX: class/interface/enum/annotation?
733: return null;
734: }
735: }
736:
737: return null;
738: }
739:
740: private static List<? extends TypeMirror> computeParametrizedType(
741: Set<ElementKind> types, CompilationInfo info,
742: TreePath parent, Tree error, int offset,
743: TypeMirror[] typeParameterBound, int[] numTypeParameters) {
744: ParameterizedTypeTree ptt = (ParameterizedTypeTree) parent
745: .getLeaf();
746:
747: if (ptt.getType() == error) {
748: types.add(ElementKind.CLASS);
749: types.add(ElementKind.INTERFACE);
750:
751: if (numTypeParameters != null) {
752: numTypeParameters[0] = ptt.getTypeArguments().size();
753: }
754: return null;
755: }
756:
757: TypeMirror resolved = info.getTrees().getTypeMirror(parent);
758: DeclaredType resolvedDT = null;
759:
760: if (resolved != null && resolved.getKind() == TypeKind.DECLARED) {
761: resolvedDT = (DeclaredType) resolved;
762: }
763:
764: int index = 0;
765:
766: for (Tree t : ptt.getTypeArguments()) {
767: if (t == error) {
768: if (resolvedDT != null && typeParameterBound != null) {
769: List<? extends TypeMirror> typeArguments = ((DeclaredType) resolvedDT
770: .asElement().asType()).getTypeArguments();
771:
772: if (typeArguments.size() > index) {
773: typeParameterBound[0] = ((TypeVariable) typeArguments
774: .get(index)).getUpperBound();
775: }
776: }
777:
778: types.add(ElementKind.CLASS); //XXX: class/interface/enum/annotation?
779: return null;
780: }
781:
782: index++;
783: }
784:
785: return null;
786: }
787:
788: private static List<? extends TypeMirror> computeClass(
789: Set<ElementKind> types, CompilationInfo info,
790: TreePath parent, Tree error, int offset) {
791: ClassTree ct = (ClassTree) parent.getLeaf();
792:
793: if (ct.getExtendsClause() == error) {
794: types.add(ElementKind.CLASS);
795: return null;
796: }
797:
798: for (Tree t : ct.getImplementsClause()) {
799: if (t == error) {
800: types.add(ElementKind.INTERFACE);
801: return null;
802: }
803: }
804:
805: //XXX: annotation types...
806:
807: return null;
808: }
809:
810: private static List<? extends TypeMirror> computeNewArray(
811: Set<ElementKind> types, CompilationInfo info,
812: TreePath parent, Tree error, int offset) {
813: NewArrayTree nat = (NewArrayTree) parent.getLeaf();
814:
815: if (nat.getType() == error) {
816: types.add(ElementKind.CLASS);
817: types.add(ElementKind.ENUM);
818: types.add(ElementKind.INTERFACE);
819:
820: return null;
821: }
822:
823: for (Tree dimension : nat.getDimensions()) {
824: if (dimension == error) {
825: types.add(ElementKind.PARAMETER);
826: types.add(ElementKind.LOCAL_VARIABLE);
827: types.add(ElementKind.FIELD);
828:
829: return Collections.singletonList(info.getTypes()
830: .getPrimitiveType(TypeKind.INT));
831: }
832: }
833:
834: for (Tree init : nat.getInitializers()) {
835: if (init == error) {
836: TypeMirror whole = info.getTrees()
837: .getTypeMirror(parent);
838:
839: if (whole == null || whole.getKind() != TypeKind.ARRAY)
840: return null;
841:
842: types.add(ElementKind.PARAMETER);
843: types.add(ElementKind.LOCAL_VARIABLE);
844: types.add(ElementKind.FIELD);
845:
846: return Collections.singletonList(((ArrayType) whole)
847: .getComponentType());
848: }
849: }
850:
851: return null;
852: }
853:
854: private static List<? extends TypeMirror> computeMethodInvocation(
855: Set<ElementKind> types, CompilationInfo info,
856: TreePath parent, Tree error, int offset) {
857: MethodInvocationTree nat = (MethodInvocationTree) parent
858: .getLeaf();
859: boolean errorInRealArguments = false;
860:
861: for (Tree param : nat.getArguments()) {
862: errorInRealArguments |= param == error;
863: }
864:
865: if (errorInRealArguments) {
866: TypeMirror[] proposedType = new TypeMirror[1];
867: int[] proposedIndex = new int[1];
868: ExecutableElement ee = org.netbeans.modules.editor.java.Utilities
869: .fuzzyResolveMethodInvocation(info, parent,
870: proposedType, proposedIndex);
871:
872: if (ee == null) { //cannot be resolved
873: return null;
874: }
875:
876: types.add(ElementKind.PARAMETER);
877: types.add(ElementKind.LOCAL_VARIABLE);
878: types.add(ElementKind.FIELD);
879:
880: return Collections.singletonList(proposedType[0]);
881: }
882:
883: return null;
884: }
885:
886: private static List<? extends TypeMirror> computeNewClass(
887: Set<ElementKind> types, CompilationInfo info,
888: TreePath parent, Tree error, int offset) {
889: NewClassTree nct = (NewClassTree) parent.getLeaf();
890: boolean errorInRealArguments = false;
891:
892: for (Tree param : nct.getArguments()) {
893: errorInRealArguments |= param == error;
894: }
895:
896: if (errorInRealArguments) {
897: TypeMirror[] proposedType = new TypeMirror[1];
898: int[] proposedIndex = new int[1];
899: ExecutableElement ee = org.netbeans.modules.editor.java.Utilities
900: .fuzzyResolveMethodInvocation(info, parent,
901: proposedType, proposedIndex);
902:
903: if (ee == null) { //cannot be resolved
904: return null;
905: }
906:
907: types.add(ElementKind.PARAMETER);
908: types.add(ElementKind.LOCAL_VARIABLE);
909: types.add(ElementKind.FIELD);
910:
911: return Collections.singletonList(proposedType[0]);
912: }
913:
914: return null;
915: }
916:
917: private static final Set<Kind> STOP_LOOKING_FOR_METHOD = EnumSet
918: .of(Kind.METHOD, Kind.CLASS, Kind.COMPILATION_UNIT);
919:
920: private static TreePath findMethod(TreePath tp) {
921: while (!STOP_LOOKING_FOR_METHOD
922: .contains(tp.getLeaf().getKind())) {
923: tp = tp.getParentPath();
924: }
925:
926: if (tp.getLeaf().getKind() == Kind.METHOD) {
927: return tp;
928: }
929:
930: return null;
931: }
932:
933: }
|