public Boolean visitNewClass(NewClassTree node, TreePath p) { if (p == null) return super.visitNewClass(node, p); NewClassTree t = (NewClassTree) p.getLeaf(); if (!scan(node.getIdentifier(), t.getIdentifier(), p)) return false; if (!scan(node.getEnclosingExpression(), t.getEnclosingExpression(), p)) return false; if (!checkLists(node.getTypeArguments(), t.getTypeArguments(), p)) return false; if (!checkLists(node.getArguments(), t.getArguments(), p)) return false; return scan(node.getClassBody(), t.getClassBody(), p); }
/** * copy the initialization 'new String("NetBeers")' to 'new String()'. * It tests only change in expression, no expression swap. */ public void testFieldChangeInInitValue() throws IOException { System.err.println("testFieldChangeInInitValue"); process( new Transformer<Void, Object>() { public Void visitVariable(VariableTree node, Object p) { super.visitVariable(node, p); if ("initialValueReplacer".contentEquals(node.getName())) { if (Tree.Kind.NEW_CLASS.equals(node.getInitializer().getKind())) { NewClassTree nct = (NewClassTree) node.getInitializer(); NewClassTree njuNct = make.NewClass( nct.getEnclosingExpression(), (List<ExpressionTree>) nct.getTypeArguments(), nct.getIdentifier(), Collections.singletonList(make.Literal("NetBeans")), nct.getClassBody() ); copy.rewrite(nct, njuNct); } } return null; } } ); assertFiles("testFieldChangeInInitValue.pass"); }
public void testWrapMethod1() throws Exception { String code = "package hierbas.del.litoral;\n\n" + "import java.util.concurrent.atomic.AtomicBoolean;\n\n" + "public class Test {\n" + "}\n"; runWrappingTest(code, new Task<WorkingCopy>() { public void run(WorkingCopy workingCopy) throws IOException { workingCopy.toPhase(Phase.RESOLVED); CompilationUnitTree cut = workingCopy.getCompilationUnit(); TreeMaker make = workingCopy.getTreeMaker(); ClassTree clazz = (ClassTree) cut.getTypeDecls().get(0); ExpressionTree parsed = workingCopy.getTreeUtilities().parseExpression("new Object() { private void test(int a, int b, int c) throws java.io.FileNotFound, java.net.MalformedURLException { } }", new SourcePositions[1]); parsed = GeneratorUtilities.get(workingCopy).importFQNs(parsed); MethodTree method = (MethodTree) ((NewClassTree) parsed).getClassBody().getMembers().get(0); workingCopy.rewrite(clazz, make.addClassMember(clazz, method)); } }, FmtOptions.wrapMethodParams, WrapStyle.WRAP_IF_LONG.name(), FmtOptions.wrapThrowsKeyword, WrapStyle.WRAP_IF_LONG.name(), FmtOptions.wrapThrowsList, WrapStyle.WRAP_IF_LONG.name()); }
public void testWrapMethod2() throws Exception { String code = "package hierbas.del.litoral;\n\n" + "import java.util.concurrent.atomic.AtomicBoolean;\n\n" + "public class Test {\n" + "}\n"; runWrappingTest(code, new Task<WorkingCopy>() { public void run(WorkingCopy workingCopy) throws IOException { workingCopy.toPhase(Phase.RESOLVED); CompilationUnitTree cut = workingCopy.getCompilationUnit(); TreeMaker make = workingCopy.getTreeMaker(); ClassTree clazz = (ClassTree) cut.getTypeDecls().get(0); ExpressionTree parsed = workingCopy.getTreeUtilities().parseExpression("new Object() { private void test(int a, int b, int c) throws java.io.FileNotFoundException, java.net.MalformedURLException { } }", new SourcePositions[1]); parsed = GeneratorUtilities.get(workingCopy).importFQNs(parsed); MethodTree method = (MethodTree) ((NewClassTree) parsed).getClassBody().getMembers().get(0); workingCopy.rewrite(clazz, make.addClassMember(clazz, method)); } }, FmtOptions.wrapMethodParams, WrapStyle.WRAP_ALWAYS.name(), FmtOptions.wrapThrowsKeyword, WrapStyle.WRAP_ALWAYS.name(), FmtOptions.wrapThrowsList, WrapStyle.WRAP_ALWAYS.name()); }
public void testWrapMethod3() throws Exception { String code = "package hierbas.del.litoral;\n\n" + "import java.util.concurrent.atomic.AtomicBoolean;\n\n" + "public class Test {\n" + "}\n"; runWrappingTest(code, new Task<WorkingCopy>() { public void run(WorkingCopy workingCopy) throws IOException { workingCopy.toPhase(Phase.RESOLVED); CompilationUnitTree cut = workingCopy.getCompilationUnit(); TreeMaker make = workingCopy.getTreeMaker(); ClassTree clazz = (ClassTree) cut.getTypeDecls().get(0); ExpressionTree parsed = workingCopy.getTreeUtilities().parseExpression("new Object() { public <T> void test(java.lang.Class<T> c) { } }", new SourcePositions[1]); parsed = GeneratorUtilities.get(workingCopy).importFQNs(parsed); MethodTree method = (MethodTree) ((NewClassTree) parsed).getClassBody().getMembers().get(0); workingCopy.rewrite(clazz, make.addClassMember(clazz, method)); } }, FmtOptions.wrapMethodParams, WrapStyle.WRAP_ALWAYS.name(), FmtOptions.wrapThrowsKeyword, WrapStyle.WRAP_ALWAYS.name(), FmtOptions.wrapThrowsList, WrapStyle.WRAP_ALWAYS.name()); }
@Override public Void visitNewClass(NewClassTree node, Stack<Tree> p) { if (instantRename) { return super.visitNewClass(node, p); } Element el = info.getTrees().getElement(getCurrentPath()); if (toFind.equals(el) && node.getIdentifier() != null) { Token<JavaTokenId> t = Utilities.getToken(info, doc, new TreePath(getCurrentPath(), node.getIdentifier())); if (t != null) usages.add(t); return null; } if (el != null && toFind.equals(el.getEnclosingElement())) { return null; } return super.visitNewClass(node, p); }
@Hint( displayName = "#DN_AnonClassMethodCount", description = "#DESC_AnonClassMethodCount", category = "metrics", options = { Hint.Options.HEAVY, Hint.Options.QUERY }, enabled = false ) @TriggerPatterns({ @TriggerPattern("new $classname<$tparams$>($params$) { $members$; }"), @TriggerPattern("$expr.new $classname<$tparams$>($params$) { $members$; }"), @TriggerPattern("new $classname($params$) { $members$; }"), @TriggerPattern("$expr.new $classname($params$) { $members$; }"), }) @UseOptions({ OPTION_ANON_CLASS_METHODS_LIMIT}) public static ErrorDescription anonymousTooManyMethods(HintContext ctx) { NewClassTree nct = (NewClassTree)ctx.getPath().getLeaf(); return checkTooManyMethods(ctx, new TreePath(ctx.getPath(), nct.getClassBody()), ctx.getPreferences().getInt(OPTION_ANON_CLASS_METHODS_LIMIT, DEFAULT_ANON_CLASS_METHODS_LIMIT), true); }
private static String className(TreePath path) { ClassTree ct = (ClassTree) path.getLeaf(); if (path.getParentPath().getLeaf().getKind() == Kind.NEW_CLASS) { NewClassTree nct = (NewClassTree) path.getParentPath().getLeaf(); if (nct.getClassBody() == ct) { return simpleName(nct.getIdentifier()); } } else if (path.getParentPath().getLeaf() == path.getCompilationUnit()) { ExpressionTree pkg = path.getCompilationUnit().getPackageName(); String pkgName = pkg != null ? pkg.toString() : null; if (pkgName != null && !pkgName.contentEquals(ERR_NAME)) { return pkgName + '.' + ct.getSimpleName().toString(); } } return ct.getSimpleName().toString(); }
public ConvertToLambdaPreconditionChecker(TreePath pathToNewClassTree, CompilationInfo info) { this.pathToNewClassTree = pathToNewClassTree; this.newClassTree = (NewClassTree) pathToNewClassTree.getLeaf(); this.info = info; this.types = info.getTypes(); Element el = info.getTrees().getElement(pathToNewClassTree); if (el != null && el.getKind() == ElementKind.CONSTRUCTOR) { createdClass = el.getEnclosingElement(); } else { createdClass = null; } this.lambdaMethodTree = getMethodFromFunctionalInterface(this.pathToNewClassTree); this.localScope = getScopeFromTree(this.pathToNewClassTree); this.ownerClass = findFieldOwner(); }
@Override public Tree visitNewClass(NewClassTree node, Trees p) { Tree t = super.visitNewClass(node, p); // new class tree > expression statement tree > block. Does not accept anonymous classes for ctor references. if (node.getClassBody() == null && singleStatementLambdaMethodBody == getCurrentPath().getParentPath().getParentPath().getLeaf()) { Tree parent = getCurrentPath().getParentPath().getLeaf(); Element el = info.getTrees().getElement(getCurrentPath()); if (el == null || el.getKind() != ElementKind.CONSTRUCTOR || !el.getEnclosingElement().getKind().isClass()) { return t; } el = el.getEnclosingElement(); if (parent.getKind() == Tree.Kind.EXPRESSION_STATEMENT || parent.getKind() == Tree.Kind.RETURN) { ExpressionTree et = node.getEnclosingExpression(); if (et != null) { if (el.getModifiers().contains(Modifier.STATIC) || !isMeaninglessQualifier(new TreePath(getCurrentPath().getParentPath(), et))) { return t; } } foundConstructorReferenceCandidate = true; } } return t; }
@Override protected void performRewrite(TransformationContext ctx) { WorkingCopy copy = ctx.getWorkingCopy(); TreePath tp = ctx.getPath(); if (tp.getLeaf().getKind() != Tree.Kind.NEW_CLASS) { //XXX: warning return ; } NewClassTree nct = (NewClassTree) tp.getLeaf(); if (nct.getIdentifier().getKind() != Tree.Kind.PARAMETERIZED_TYPE) { //XXX: warning return ; } TreeMaker make = copy.getTreeMaker(); ParameterizedTypeTree ptt = (ParameterizedTypeTree) nct.getIdentifier(); ParameterizedTypeTree nue = make.ParameterizedType(ptt.getType(), Collections.<Tree>emptyList()); copy.rewrite(ptt, nue); }
@TriggerPatterns({ @TriggerPattern("new $clazz($params$) { $method; }") //NOI18N }) @NbBundle.Messages("MSG_AnonymousConvertibleToLambda=This anonymous inner class creation can be turned into a lambda expression.") public static ErrorDescription computeAnnonymousToLambda(HintContext ctx) { ClassTree clazz = ((NewClassTree) ctx.getPath().getLeaf()).getClassBody(); ConvertToLambdaPreconditionChecker preconditionChecker = new ConvertToLambdaPreconditionChecker(ctx.getPath(), ctx.getInfo()); if (!preconditionChecker.passesFatalPreconditions()) { return null; } FixImpl fix = new FixImpl(ctx.getInfo(), ctx.getPath(), false); if (ctx.getPreferences().getBoolean(KEY_PREFER_MEMBER_REFERENCES, DEF_PREFER_MEMBER_REFERENCES) && (preconditionChecker.foundMemberReferenceCandidate() || preconditionChecker.foundConstructorReferenceCandidate())) { return ErrorDescriptionFactory.forTree(ctx, ((NewClassTree) ctx.getPath().getLeaf()).getIdentifier(), Bundle.MSG_AnonymousConvertibleToLambda(), new FixImpl(ctx.getInfo(), ctx.getPath(), true).toEditorFix(), fix.toEditorFix()); } return ErrorDescriptionFactory.forTree(ctx, ((NewClassTree) ctx.getPath().getLeaf()).getIdentifier(), Bundle.MSG_AnonymousConvertibleToLambda(), fix.toEditorFix()); }
@Override protected void performRewrite(TransformationContext ctx) throws Exception { TreePath p = ctx.getPath(); if (p.getLeaf().getKind() != Tree.Kind.NEW_CLASS) { return; } NewClassTree origNct = (NewClassTree)p.getLeaf(); if (origNct.getArguments().size() != 1) { return; } NewClassTree nct = GeneratorUtilities.get(ctx.getWorkingCopy()).importComments(origNct, ctx.getWorkingCopy().getCompilationUnit()); ExpressionTree charArg = nct.getArguments().get(0); TreeMaker mk = ctx.getWorkingCopy().getTreeMaker(); ExpressionTree newExpr = mk.NewClass(nct.getEnclosingExpression(), (List<ExpressionTree>)nct.getTypeArguments(), nct.getIdentifier(), Collections.<ExpressionTree>emptyList(), nct.getClassBody()); Tree replace = mk.MethodInvocation( Collections.<ExpressionTree>emptyList(), mk.MemberSelect(newExpr, "append"), // NOI18N Collections.singletonList(charArg)); ctx.getWorkingCopy().rewrite(nct, replace); }
@Override public Boolean visitNewClass(NewClassTree node, Void p) { TypeMirror tm = ci.getTrees().getTypeMirror(getCurrentPath()); if (tm == null || tm.getKind() != TypeKind.DECLARED) { return false; } TypeElement el = (TypeElement)((DeclaredType)tm).asElement(); if (el == null) { return false; } Name n = el.getQualifiedName(); boolean res = n.contentEquals("java.lang.StringBuilder") || n.contentEquals("java.lang.StringBuffer"); // NOI18N // check if there is some initial contents if (node.getArguments().size() == 1 && Utilities.isJavaString(ci, ci.getTrees().getTypeMirror(new TreePath(getCurrentPath(), node.getArguments().get(0))))) { hasContents = true; } return res; }
private ExpressionTree rewriteNewClass(TreePath p) { ExpressionTree expr = (ExpressionTree) p.getLeaf(); NewClassTree nct = (NewClassTree) expr; Element el = wc.getTrees().getElement(p); if (el != null && el.getKind() == ElementKind.CONSTRUCTOR) { ExecutableElement ee = (ExecutableElement) el; if (ee.getParameters().isEmpty()) { // ctor without parameters, remove return null; } TypeMirror argType = ee.getParameters().get(0).asType(); if (argType.getKind() == TypeKind.DECLARED) { ExpressionTree a = nct.getArguments().get(0); gu.copyComments(expr, a, true); gu.copyComments(expr, a, false); wc.rewrite(expr, a); return a; } return null; } return expr; }
@Override public Object visitNewClass(NewClassTree node, Object p) { Element e = ci.getTrees().getElement(getCurrentPath()); if (e != null && e.getKind() == ElementKind.CONSTRUCTOR) { addInstanceForConstructor(e); } Object r = scan(node.getEnclosingExpression(), p); r = scanAndReduce(node.getIdentifier(), p, r); r = scanAndReduce(node.getTypeArguments(), p, r); r = scanAndReduce(node.getArguments(), p, r); // switch context to the anonymous class if (e != null) { TypeElement saveType = enclosingType; enclosingType = ci.getElementUtilities().enclosingTypeElement(e); r = scanAndReduce(node.getClassBody(), p, r); this.enclosingType = saveType; } return r; }
@Override public Object visitNewClass(NewClassTree node, Object p) { Element e = ctx.getInfo().getTrees().getElement(getCurrentPath()); if (e == null) { return super.visitNewClass(node, p); } else { e = e.getEnclosingElement(); } if (e != null && e.getKind().isClass()) { Object r = scan(node.getEnclosingExpression(), p); r = scanAndReduce(node.getIdentifier(), p, r); r = scanAndReduce(node.getTypeArguments(), p, r); r = scanAndReduce(node.getArguments(), p, r); nestingLevel++; enclosingElements.push((TypeElement) e); r = scanAndReduce(node.getClassBody(), p, r); nestingLevel--; enclosingElements.pop(); return r; } else { return super.visitNewClass(node, p); } }
/** * Returns the Element which is incomplete, or, for anonymous classes, * returns the extended TypeElement (which is also incomplete). This is because * an Element is not available for the incomplete class. */ private static TypeElement findTypeElement(CompilationInfo info, TreePath path) { Element e = info.getTrees().getElement(path); if (e == null) { return null; } else if (e.getKind().isClass() || e.getKind().isInterface()) { return (TypeElement)e; } TypeMirror tm = info.getTrees().getTypeMirror(path); if (tm == null || tm.getKind() != TypeKind.DECLARED) { if (path.getLeaf().getKind() == Tree.Kind.NEW_CLASS) { tm = info.getTrees().getTypeMirror(new TreePath(path, ((NewClassTree)path.getLeaf()).getIdentifier())); } } if (tm != null && tm.getKind() == TypeKind.DECLARED) { return (TypeElement)((DeclaredType)tm).asElement(); } else { return null; } }
protected boolean generateClassBody(TreePath p) throws Exception { Element e = copy.getTrees().getElement(p); boolean isUsableElement = e != null && (e.getKind().isClass() || e.getKind().isInterface()); if (isUsableElement) { return true; } if (e.getKind() == ElementKind.ENUM_CONSTANT) { VariableTree var = (VariableTree) p.getLeaf(); if (var.getInitializer() != null && var.getInitializer().getKind() == Kind.NEW_CLASS) { NewClassTree nct = (NewClassTree) var.getInitializer(); if (nct.getClassBody() != null) { return true; } } } return !generateClassBody2(copy, p); }
/** * Attempts to resolve a method or a constructor call with an altered argument tree. * * @param ci the context * @param invPath path to the method invocation node * @param origPath path to the Tree within method's arguments which should be replaced * @param valPath the replacement tree * @return */ public static boolean checkAlternativeInvocation(CompilationInfo ci, TreePath invPath, TreePath origPath, TreePath valPath, String customPrefix) { Tree l = invPath.getLeaf(); Tree sel; if (l.getKind() == Tree.Kind.NEW_CLASS) { NewClassTree nct = (NewClassTree)invPath.getLeaf(); sel = nct.getIdentifier(); } else if (l.getKind() == Tree.Kind.METHOD_INVOCATION) { MethodInvocationTree mit = (MethodInvocationTree)invPath.getLeaf(); sel = mit.getMethodSelect(); } else { return false; } return resolveAlternativeInvocation(ci, invPath, origPath, sel, valPath, customPrefix); }
@Override public List<? extends TypeMirror> visitNewClass(NewClassTree node, Object p) { TypeMirror tm = info.getTrees().getTypeMirror(getCurrentPath()); if (tm == null || tm.getKind() != TypeKind.DECLARED) { return null; } Element el = info.getTrees().getElement(getCurrentPath()); if (el == null) { return null; } if (theExpression.getLeaf() != node.getEnclosingExpression()) { ExecutableType execType = (ExecutableType)info.getTypes().asMemberOf((DeclaredType)tm, el); return visitMethodOrNew(node, p, node.getArguments(), execType); } else { DeclaredType dt = (DeclaredType)tm; if (dt.getEnclosingType() == null) { return null; } return Collections.singletonList(dt.getEnclosingType()); } }
/** * Checks whether a method or constructor call would become ambiguous if the parameter type changes. * * @param info compilation context * @param parentExec path to the constructor or method invocation * @param argIndex * @param casteeType * @return */ private static boolean checkAmbiguous(CompilationInfo info, final TreePath parentExec, int argIndex, TypeMirror casteeType, TreePath realArgTree) { CharSequence altType = info.getTypeUtilities().getTypeName(casteeType, TypeUtilities.TypeNameOptions.PRINT_FQN); String prefix = null; if (casteeType != null && !(casteeType.getKind() == TypeKind.NULL || casteeType.getKind() == TypeKind.INTERSECTION)) { prefix = "(" + altType + ")"; // NOI18N } Tree leaf = parentExec.getLeaf(); List<? extends Tree> arguments; if (leaf instanceof MethodInvocationTree) { MethodInvocationTree mi = (MethodInvocationTree)leaf; arguments = mi.getArguments(); } else { arguments = ((NewClassTree)leaf).getArguments(); } Tree argTree = arguments.get(argIndex); TreePath argPath = new TreePath(parentExec, argTree); return !Utilities.checkAlternativeInvocation(info, parentExec, argPath, realArgTree, prefix); }
private Element elementOf(Node n) { Tree t = n.getTree(); if (t instanceof ExpressionTree) { return TreeUtils.elementFromUse((ExpressionTree)t); } else if (t instanceof MethodInvocationTree) { return TreeUtils.elementFromUse((MethodInvocationTree)t); } else if (t instanceof NewClassTree) { return TreeUtils.elementFromUse((NewClassTree)t); } else if (t instanceof VariableTree) { return TreeUtils.elementFromDeclaration((VariableTree)t); } else if (t instanceof MethodTree) { return TreeUtils.elementFromDeclaration((MethodTree)t); } else if (t instanceof ClassTree) { return TreeUtils.elementFromDeclaration((ClassTree)t); } else { throw new RuntimeException("Unsupported tree type " + t.getClass()); } }
@Override public Description matchNewClass(NewClassTree tree, VisitorState state) { if (!matchWithinClass) { return Description.NO_MATCH; } Symbol.MethodSymbol methodSymbol = ASTHelpers.getSymbol(tree); if (methodSymbol == null) { throw new RuntimeException("not expecting unresolved method here"); } List<? extends ExpressionTree> actualParams = tree.getArguments(); if (tree.getClassBody() != null && actualParams.size() > 0) { // passing parameters to constructor of anonymous class // this constructor just invokes the constructor of the superclass, and // in the AST does not have the parameter nullability annotations from the superclass. // so, treat as if the superclass constructor is being invoked directly // see https://github.com/uber/NullAway/issues/102 Type supertype = state.getTypes().supertype(methodSymbol.owner.type); Symbol.MethodSymbol superConstructor = findSuperConstructorInType(methodSymbol, supertype, state.getTypes()); if (superConstructor == null) { throw new RuntimeException("must find constructor in supertype"); } methodSymbol = superConstructor; } return handleInvocation(state, methodSymbol, actualParams); }
@Override public Void visitNewClass(NewClassTree node, Void unused) { sync(node); builder.open(ZERO); if (node.getEnclosingExpression() != null) { scan(node.getEnclosingExpression(), null); builder.breakOp(); token("."); } token("new"); builder.space(); addTypeArguments(node.getTypeArguments(), plusFour); if (node.getClassBody() != null) { List<Op> ops = visitModifiers(node.getClassBody().getModifiers(), Direction.HORIZONTAL, Optional.<BreakTag>absent()); builder.addAll(ops); } scan(node.getIdentifier(), null); addArguments(node.getArguments(), plusFour); builder.close(); if (node.getClassBody() != null) { addBodyDeclarations( node.getClassBody().getMembers(), BracesOrNot.YES, FirstDeclarationsOrNot.YES); } return null; }
private void visitEnumConstantDeclaration(VariableTree enumConstant) { for (AnnotationTree annotation : enumConstant.getModifiers().getAnnotations()) { scan(annotation, null); builder.forcedBreak(); } visit(enumConstant.getName()); NewClassTree init = ((NewClassTree) enumConstant.getInitializer()); if (init.getArguments().isEmpty()) { builder.guessToken("("); builder.guessToken(")"); } else { addArguments(init.getArguments(), plusFour); } if (init.getClassBody() != null) { addBodyDeclarations( init.getClassBody().getMembers(), BracesOrNot.YES, FirstDeclarationsOrNot.YES); } }
private SignatureHelp constructorHelp(NewClassTree leaf) { Trees trees = Trees.instance(task); TreePath identifierPath = TreePath.getPath(cursor.getCompilationUnit(), leaf.getIdentifier()); Element classElement = trees.getElement(identifierPath); List<ExecutableElement> candidates = classElement .getEnclosedElements() .stream() .filter(member -> member.getKind() == ElementKind.CONSTRUCTOR) .map(method -> (ExecutableElement) method) .collect(Collectors.toList()); List<SignatureInformation> signatures = candidates .stream() .map(member -> constructorInfo(member)) .collect(Collectors.toList()); int activeSignature = candidates.indexOf(classElement); return new SignatureHelp( signatures, activeSignature < 0 ? null : activeSignature, activeParameter(leaf.getArguments())); }
@Test public void buildTreeWithConstructorParamsInitializer() throws FileNotFoundException, ParseException { ApexParser parser = getParser("ClassWithInitializers.cls"); CompilationUnitTree compilationUnit = parser.CompilationUnit(); List<VariableTree> varList = TreeNavigationUtils.findVariableTreeByName("secondA", compilationUnit); assertEquals(1, varList.size()); ExpressionTree initializer = varList.get(0).getInitializer(); assertEquals(Kind.NEW_CLASS , initializer.getKind()); NewClassTree classInitializer = (NewClassTree)initializer; assertTrue(((IdentifierTree)classInitializer.getIdentifier()).getName().equals("A")); assertTrue(classInitializer.getTypeArguments().isEmpty()); assertFalse(classInitializer.getArguments().isEmpty()); assertEquals(2, classInitializer.getArguments().size()); IdentifierTree arg = (IdentifierTree)classInitializer.getArguments().get(0); assertTrue(arg.getName().equals("arg1")); arg = (IdentifierTree)classInitializer.getArguments().get(1); assertTrue(arg.getName().equals("arg2")); }
@Test public void buildTreeWithListInitializer() throws FileNotFoundException, ParseException { ApexParser parser = getParser("ClassWithInitializers.cls"); CompilationUnitTree compilationUnit = parser.CompilationUnit(); List<VariableTree> varList = TreeNavigationUtils.findVariableTreeByName("firstList", compilationUnit); assertEquals(1, varList.size()); ExpressionTree initializer = varList.get(0).getInitializer(); assertEquals(Kind.NEW_CLASS , initializer.getKind()); NewClassTree listInitializer = (NewClassTree)initializer; assertTrue(listInitializer.getArguments().isEmpty()); assertTrue(((IdentifierTree)listInitializer.getIdentifier()).getName().equals("List")); assertFalse(listInitializer.getTypeArguments().isEmpty()); assertEquals(1, listInitializer.getTypeArguments().size()); IdentifierTree typeArgument = (IdentifierTree) listInitializer.getTypeArguments().get(0); assertTrue(typeArgument.getName().equals("B")); }
@Test public void buildTreeWithListAndInitializers() throws FileNotFoundException, ParseException { ApexParser parser = getParser("ClassWithInitializers.cls"); CompilationUnitTree compilationUnit = parser.CompilationUnit(); List<VariableTree> varList = TreeNavigationUtils.findVariableTreeByName("secondList", compilationUnit); assertEquals(1, varList.size()); ExpressionTree initializer = varList.get(0).getInitializer(); assertEquals(Kind.NEW_CLASS , initializer.getKind()); NewClassTree listInitializer = (NewClassTree)initializer; assertTrue(((IdentifierTree)listInitializer.getIdentifier()).getName().equals("List")); assertFalse(listInitializer.getTypeArguments().isEmpty()); assertEquals(1, listInitializer.getTypeArguments().size()); IdentifierTree typeArgument = (IdentifierTree) listInitializer.getTypeArguments().get(0); assertTrue(typeArgument.getName().equals("B")); assertFalse(listInitializer.getArguments().isEmpty()); assertEquals(3, listInitializer.getArguments().size()); IdentifierTree paramArgument = (IdentifierTree) listInitializer.getArguments().get(0); assertTrue(paramArgument.getName().equals("b1")); paramArgument = (IdentifierTree) listInitializer.getArguments().get(1); assertTrue(paramArgument.getName().equals("b2")); paramArgument = (IdentifierTree) listInitializer.getArguments().get(2); assertTrue(paramArgument.getName().equals("b3")); }
@Test public void buildTreeWithSetAndInitializers() throws FileNotFoundException, ParseException { ApexParser parser = getParser("ClassWithInitializers.cls"); CompilationUnitTree compilationUnit = parser.CompilationUnit(); List<VariableTree> varList = TreeNavigationUtils.findVariableTreeByName("mySet", compilationUnit); assertEquals(1, varList.size()); ExpressionTree initializer = varList.get(0).getInitializer(); assertEquals(Kind.NEW_CLASS , initializer.getKind()); NewClassTree setInitializer = (NewClassTree)initializer; assertTrue(((IdentifierTree)setInitializer.getIdentifier()).getName().equals("Set")); assertFalse(setInitializer.getTypeArguments().isEmpty()); assertEquals(1, setInitializer.getTypeArguments().size()); IdentifierTree typeArgument = (IdentifierTree) setInitializer.getTypeArguments().get(0); assertTrue(typeArgument.getName().equals("C")); assertFalse(setInitializer.getArguments().isEmpty()); assertEquals(3, setInitializer.getArguments().size()); IdentifierTree paramArgument = (IdentifierTree) setInitializer.getArguments().get(0); assertTrue(paramArgument.getName().equals("c1")); paramArgument = (IdentifierTree) setInitializer.getArguments().get(1); assertTrue(paramArgument.getName().equals("c2")); paramArgument = (IdentifierTree) setInitializer.getArguments().get(2); assertTrue(paramArgument.getName().equals("c3")); }
@Override public Pair<ASTRecord, Integer> visitNewClass(NewClassTree node, Insertion ins) { JCNewClass na = (JCNewClass) node; JCExpression className = na.clazz; // System.out.printf("classname %s (%s)%n", className, className.getClass()); while (! (className.getKind() == Tree.Kind.IDENTIFIER)) { // IdentifierTree if (className instanceof JCAnnotatedType) { className = ((JCAnnotatedType) className).underlyingType; } else if (className instanceof JCTypeApply) { className = ((JCTypeApply) className).clazz; } else if (className instanceof JCFieldAccess) { // This occurs for fully qualified names, e.g. "new java.lang.Object()". // I'm not quite sure why the field "selected" is taken, but "name" would // be a type mismatch. It seems to work, see NewPackage test case. className = ((JCFieldAccess) className).selected; } else { throw new Error(String.format("unrecognized JCNewClass.clazz (%s): %s%n" + " surrounding new class tree: %s%n", className.getClass(), className, node)); } // System.out.printf("classname %s (%s)%n", className, className.getClass()); } return visitIdentifier((IdentifierTree) className, ins); }
@Override public Void visitNewClass(NewClassTree node, Integer level) { // if (level < 2) { if (!found && anonclass.getKind() == Tree.Kind.NEW_CLASS) { if (anonclass == node) { found = true; } else if (node.getClassBody() != null) { // Need to make sure you actually are creating anonymous inner class, // not just object creation. index++; } else { return null; } } super.visitNewClass(node, level + 1); // } return null; }
@Override public Optional<MatchState> matchResult(ExpressionTree tree, VisitorState state) { Symbol sym = ASTHelpers.getSymbol(tree); if (!(sym instanceof MethodSymbol)) { return Optional.absent(); } if (tree instanceof NewClassTree) { // Don't match constructors as they are neither static nor instance methods. return Optional.absent(); } if (tree instanceof MethodInvocationTree) { tree = ((MethodInvocationTree) tree).getMethodSelect(); } return Optional.of( MatchState.create(ASTHelpers.getReceiverType(tree), (MethodSymbol) sym)); }
/** * Gets the symbol for a tree. Returns null if this tree does not have a symbol because it is of * the wrong type, if {@code tree} is null, or if the symbol cannot be found due to a compilation * error. */ // TODO(eaftan): refactor other code that accesses symbols to use this method public static Symbol getSymbol(Tree tree) { if (tree instanceof JCFieldAccess) { return ((JCFieldAccess) tree).sym; } if (tree instanceof JCIdent) { return ((JCIdent) tree).sym; } if (tree instanceof JCMethodInvocation) { return ASTHelpers.getSymbol((MethodInvocationTree) tree); } if (tree instanceof JCNewClass) { return ASTHelpers.getSymbol((NewClassTree) tree); } if (tree instanceof MemberReferenceTree) { return ((JCMemberReference) tree).sym; } if (tree instanceof JCAnnotatedType) { return getSymbol(((JCAnnotatedType) tree).underlyingType); } return getDeclaredSymbol(tree); }
@Override public Description matchNewClass(NewClassTree newClassTree, VisitorState state) { if (!MATCHER.matches(newClassTree, state)) { return Description.NO_MATCH; } StatementTree parent = (StatementTree) state.getPath().getParentPath().getLeaf(); boolean isLastStatement = anyOf( new ChildOfBlockOrCase<>( ChildMultiMatcher.MatchType.LAST, Matchers.<StatementTree>isSame(parent)), // it could also be a bare if statement with no braces parentNode(parentNode(kindIs(IF)))) .matches(newClassTree, state); Fix fix; if (isLastStatement) { fix = SuggestedFix.prefixWith(newClassTree, "throw "); } else { fix = SuggestedFix.delete(parent); } return describeMatch(newClassTree, fix); }
@Override public boolean matches(Tree tree, VisitorState visitorState) { if (!(tree instanceof NewClassTree)) { return false; } NewClassTree newClassTree = (NewClassTree) tree; if (newClassTree.getClassBody() == null) { return false; } return newClassTree .getClassBody() .getMembers() .stream() .filter(mem -> mem instanceof VariableTree) .anyMatch(mem -> !isFinal(mem)); }
@Override public Description matchNewClass(NewClassTree tree, VisitorState state) { Symbol sym = ASTHelpers.getSymbol(tree.getIdentifier()); if (sym == null) { return NO_MATCH; } Types types = state.getTypes(); Symtab symtab = state.getSymtab(); // TODO(cushon): consider handling String also if (sym.equals(types.boxedClass(symtab.byteType)) || sym.equals(types.boxedClass(symtab.charType)) || sym.equals(types.boxedClass(symtab.shortType)) || sym.equals(types.boxedClass(symtab.intType)) || sym.equals(types.boxedClass(symtab.longType)) || sym.equals(types.boxedClass(symtab.doubleType)) || sym.equals(types.boxedClass(symtab.floatType)) || sym.equals(types.boxedClass(symtab.booleanType))) { return describeMatch(tree, buildFix(tree, state)); } return NO_MATCH; }
/** Ignore some common ThreadLocal type arguments that are fine to have per-instance copies of. */ private boolean wellKnownTypeArgument(NewClassTree tree, VisitorState state) { Type type = getType(tree); if (type == null) { return false; } type = state.getTypes().asSuper(type, state.getSymbolFromString("java.lang.ThreadLocal")); if (type == null) { return false; } if (type.getTypeArguments().isEmpty()) { return false; } Type argType = getOnlyElement(type.getTypeArguments()); if (WELL_KNOWN_TYPES.contains(argType.asElement().getQualifiedName().toString())) { return true; } if (isSubtype(argType, state.getTypeFromString("java.text.DateFormat"), state)) { return true; } return false; }
@Override public Description matchNewClass(NewClassTree tree, VisitorState state) { // check instantiations of `@ImmutableTypeParameter`s in generic constructor invocations checkInvocation( tree, ((JCNewClass) tree).constructorType, state, ((JCNewClass) tree).constructor); // check instantiations of `@ImmutableTypeParameter`s in class constructor invocations ImmutableAnalysis analysis = new ImmutableAnalysis(this, state, wellKnownMutability); Violation info = analysis.checkInstantiation( ASTHelpers.getSymbol(tree.getIdentifier()).getTypeParameters(), ASTHelpers.getType(tree).getTypeArguments()); if (info.isPresent()) { state.reportMatch(buildDescription(tree).setMessage(info.message()).build()); } return NO_MATCH; }