| /******************************************************************************* |
| * Copyright (c) 2019, 2020 IBM Corporation and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.jdt.internal.ui.text.correction.proposals; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| import org.eclipse.core.runtime.CoreException; |
| |
| import org.eclipse.jdt.core.ICompilationUnit; |
| import org.eclipse.jdt.core.dom.AST; |
| import org.eclipse.jdt.core.dom.ASTNode; |
| import org.eclipse.jdt.core.dom.ASTVisitor; |
| import org.eclipse.jdt.core.dom.AbstractTypeDeclaration; |
| import org.eclipse.jdt.core.dom.Assignment; |
| import org.eclipse.jdt.core.dom.Block; |
| import org.eclipse.jdt.core.dom.ClassInstanceCreation; |
| import org.eclipse.jdt.core.dom.CompilationUnit; |
| import org.eclipse.jdt.core.dom.Expression; |
| import org.eclipse.jdt.core.dom.ExpressionStatement; |
| import org.eclipse.jdt.core.dom.FieldAccess; |
| import org.eclipse.jdt.core.dom.FieldDeclaration; |
| import org.eclipse.jdt.core.dom.IBinding; |
| import org.eclipse.jdt.core.dom.IMethodBinding; |
| import org.eclipse.jdt.core.dom.ITypeBinding; |
| import org.eclipse.jdt.core.dom.IVariableBinding; |
| import org.eclipse.jdt.core.dom.MethodDeclaration; |
| import org.eclipse.jdt.core.dom.Modifier; |
| import org.eclipse.jdt.core.dom.ParameterizedType; |
| import org.eclipse.jdt.core.dom.PrimitiveType; |
| import org.eclipse.jdt.core.dom.RecordDeclaration; |
| import org.eclipse.jdt.core.dom.SimpleName; |
| import org.eclipse.jdt.core.dom.SingleVariableDeclaration; |
| import org.eclipse.jdt.core.dom.Type; |
| import org.eclipse.jdt.core.dom.VariableDeclarationFragment; |
| import org.eclipse.jdt.core.dom.rewrite.ASTRewrite; |
| import org.eclipse.jdt.core.dom.rewrite.ImportRewrite; |
| |
| import org.eclipse.jdt.internal.core.manipulation.StubUtility; |
| import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory; |
| import org.eclipse.jdt.internal.corext.dom.ASTNodes; |
| import org.eclipse.jdt.internal.corext.util.Messages; |
| |
| import org.eclipse.jdt.ui.text.java.IProblemLocation; |
| |
| import org.eclipse.jdt.internal.ui.JavaPluginImages; |
| import org.eclipse.jdt.internal.ui.text.correction.CorrectionMessages; |
| import org.eclipse.jdt.internal.ui.util.ASTHelper; |
| |
| public class InitializeFinalFieldProposal extends LinkedCorrectionProposal { |
| private IProblemLocation fProblem; |
| |
| private ASTNode fAstNode; |
| |
| private final IVariableBinding fVariableBinding; |
| |
| private int fupdateType; |
| |
| public static final int UPDATE_AT_DECLARATION= 0; |
| |
| public static final int UPDATE_AT_CONSTRUCTOR= 1; |
| |
| public static final int UPDATE_CONSTRUCTOR_NEW_PARAMETER= 2; |
| |
| public InitializeFinalFieldProposal(IProblemLocation problem, ICompilationUnit cu, ASTNode astNode, IVariableBinding variableBinding, int relevance) { |
| super(Messages.format(CorrectionMessages.InitializeFieldAtDeclarationCorrectionProposal_description, problem.getProblemArguments()[0]), cu, null, relevance, null); |
| |
| fProblem= problem; |
| fAstNode= astNode; |
| fVariableBinding= variableBinding; |
| fupdateType= UPDATE_AT_DECLARATION; |
| setImage(JavaPluginImages.get(JavaPluginImages.IMG_FIELD_PRIVATE)); |
| } |
| |
| public InitializeFinalFieldProposal(IProblemLocation problem, ICompilationUnit cu, ASTNode astNode, int relevance, int updateType) { |
| super(Messages.format(CorrectionMessages.InitializeFieldInConstructorCorrectionProposal_description, problem.getProblemArguments()[0]), cu, null, relevance, null); |
| if (updateType == UPDATE_CONSTRUCTOR_NEW_PARAMETER) { |
| setDisplayName(Messages.format(CorrectionMessages.InitializeFieldWithConstructorParameterCorrectionProposal_description, problem.getProblemArguments()[0])); |
| } |
| |
| fProblem= problem; |
| fAstNode= astNode; |
| fVariableBinding= null; |
| fupdateType= updateType; |
| setImage(JavaPluginImages.get(JavaPluginImages.IMG_FIELD_PRIVATE)); |
| } |
| |
| public boolean hasProposal() throws CoreException { |
| return getRewrite() != null; |
| } |
| |
| @Override |
| protected ASTRewrite getRewrite() throws CoreException { |
| switch (fupdateType) { |
| case UPDATE_AT_CONSTRUCTOR: |
| if (fAstNode != null |
| && fAstNode.getParent() instanceof RecordDeclaration |
| && ASTHelper.isRecordDeclarationNodeSupportedInAST(fAstNode.getAST())) { |
| return doInitRecordComponentsInConstructor(); |
| } |
| return doInitFieldInConstructor(); |
| case UPDATE_AT_DECLARATION: |
| return doInitField(); |
| case UPDATE_CONSTRUCTOR_NEW_PARAMETER: |
| return doUpdateConstructorWithParameter(); |
| default: |
| break; |
| } |
| return null; |
| } |
| |
| private ASTRewrite doInitField() { |
| FieldDeclaration field= getFieldDeclaration(fVariableBinding.getName()); |
| if (field == null) { |
| return null; |
| } |
| AST ast= fAstNode.getAST(); |
| |
| ITypeBinding type= fVariableBinding.getType(); |
| String variableTypeName= type.getName(); |
| |
| VariableDeclarationFragment newFragment= ast.newVariableDeclarationFragment(); |
| newFragment.setName(ast.newSimpleName(fVariableBinding.getName())); |
| |
| FieldDeclaration declaration= ast.newFieldDeclaration(newFragment); |
| declaration.modifiers().addAll(ast.newModifiers(fVariableBinding.getModifiers())); |
| |
| Expression expression= null; |
| if (type.isPrimitive()) { |
| declaration.setType(ast.newPrimitiveType(PrimitiveType.toCode(variableTypeName))); |
| expression= ast.newNumberLiteral(); |
| } else if ("String".equals(variableTypeName)) { //$NON-NLS-1$ |
| declaration.setType(ast.newSimpleType(ast.newName(variableTypeName))); |
| expression= ast.newStringLiteral(); |
| } else { |
| Type newType= null; |
| if (type.isParameterizedType()) { |
| newType= createParameterizedType(ast, type); |
| } else { |
| newType= ast.newSimpleType(ast.newName(variableTypeName)); |
| } |
| declaration.setType(newType); |
| |
| if (hasDefaultConstructor()) { |
| ClassInstanceCreation cic= ast.newClassInstanceCreation(); |
| cic.setType((Type) ASTNode.copySubtree(ast, newType)); |
| expression= cic; |
| } else { |
| expression= ast.newNullLiteral(); |
| } |
| } |
| newFragment.setInitializer(expression); |
| |
| ASTRewrite rewrite= ASTRewrite.create(ast); |
| rewrite.replace(field, declaration, null); |
| setEndPosition(rewrite.track(expression)); // set cursor after expression statement |
| return rewrite; |
| } |
| |
| private Type createParameterizedType(AST ast, ITypeBinding typeBinding) { |
| if (typeBinding.isParameterizedType() && !typeBinding.isRawType()) { |
| Type baseType= ast.newSimpleType(ASTNodeFactory.newName(ast, typeBinding.getErasure().getName())); |
| ParameterizedType newType= ast.newParameterizedType(baseType); |
| for (int i= 0; i < typeBinding.getTypeArguments().length; i++) { |
| ITypeBinding typeArg= typeBinding.getTypeArguments()[i]; |
| Type argType= createParameterizedType(ast, typeArg); // recursive call |
| newType.typeArguments().add(argType); |
| } |
| return newType; |
| } else { |
| if (!typeBinding.isTypeVariable()) { |
| if (typeBinding.isWildcardType()) { |
| ImportRewrite importRewrite= createImportRewrite((CompilationUnit) fAstNode.getRoot()); |
| return importRewrite.addImport(typeBinding, ast); |
| } |
| return ast.newSimpleType(ASTNodeFactory.newName(ast, typeBinding.getErasure().getName())); |
| } |
| return ast.newSimpleType(ast.newSimpleName(typeBinding.getName())); |
| } |
| } |
| |
| private ASTRewrite doInitRecordComponentsInConstructor() { |
| String variableName= fProblem.getProblemArguments()[0]; |
| SingleVariableDeclaration svd= getRecordComponentDeclaration(variableName); |
| if (svd == null) { |
| return null; |
| } |
| AST ast= svd.getAST(); |
| |
| FieldAccess fieldAccess= ast.newFieldAccess(); |
| fieldAccess.setName(ast.newSimpleName(variableName)); |
| fieldAccess.setExpression(ast.newThisExpression()); |
| |
| Assignment assignment= ast.newAssignment(); |
| assignment.setLeftHandSide(fieldAccess); |
| assignment.setOperator(Assignment.Operator.ASSIGN); |
| |
| Type fieldType= svd.getType(); |
| if (fieldType.isPrimitiveType()) { |
| assignment.setRightHandSide(ast.newNumberLiteral()); |
| } else if ("String".equals(fieldType.toString())) { //$NON-NLS-1$ |
| assignment.setRightHandSide(ast.newStringLiteral()); |
| } else { |
| if (hasDefaultConstructor(fieldType.resolveBinding())) { |
| ClassInstanceCreation cic= ast.newClassInstanceCreation(); |
| cic.setType(ast.newSimpleType(ast.newName(fieldType.toString()))); |
| assignment.setRightHandSide(cic); |
| } else { |
| assignment.setRightHandSide(ast.newNullLiteral()); |
| } |
| } |
| ExpressionStatement statement= ast.newExpressionStatement(assignment); |
| |
| ASTRewrite rewrite= ASTRewrite.create(ast); |
| // find all constructors (methods with same name as the type name) |
| ConstructorVisitor cv= new ConstructorVisitor(((RecordDeclaration) svd.getParent()).getName().toString()); |
| fAstNode.getRoot().accept(cv); |
| |
| for (MethodDeclaration md : cv.getNodes()) { |
| if (!isCanonical(md)) { |
| continue; |
| } |
| Block body= md.getBody(); |
| rewrite.getListRewrite(body, Block.STATEMENTS_PROPERTY).insertAt(statement, 0, null); |
| setEndPosition(rewrite.track(assignment)); // set cursor after expression statement |
| } |
| return rewrite; |
| } |
| |
| private boolean isCanonical(MethodDeclaration md) { |
| IMethodBinding methodBinding= md.resolveBinding(); |
| return ((methodBinding == null) ? false : methodBinding.isCanonicalConstructor()); |
| } |
| |
| private ASTRewrite doUpdateConstructorWithParameter() { |
| String variableName= fProblem.getProblemArguments()[0]; |
| FieldDeclaration field= getFieldDeclaration(variableName); |
| if (field == null) { |
| return null; |
| } |
| Type fieldType= field.getType(); |
| ITypeBinding fieldBinding= fieldType.resolveBinding(); |
| if (fieldBinding == null) { |
| return null; |
| } |
| // find all constructors (methods with same name as the type name) |
| ConstructorVisitor cv= new ConstructorVisitor(((AbstractTypeDeclaration) field.getParent()).getName().toString()); |
| fAstNode.getRoot().accept(cv); |
| if (cv.getNodes().size() != 1) { // we only handle the simple case of one constructor |
| return null; |
| } |
| MethodDeclaration methodDeclaration= cv.getNodes().get(0); // only one constructor |
| IMethodBinding methodBinding= methodDeclaration.resolveBinding(); |
| if (methodBinding == null) { |
| return null; |
| } |
| AST ast= field.getAST(); |
| ASTRewrite rewrite= ASTRewrite.create(ast); |
| |
| SingleVariableDeclaration newSingleVariableDeclaration= ast.newSingleVariableDeclaration(); |
| |
| String[] excludedNames= collectParameterNames(methodDeclaration); |
| String newName= StubUtility.suggestArgumentName(getCompilationUnit().getJavaProject(), variableName, excludedNames); |
| |
| newSingleVariableDeclaration.setName(ast.newSimpleName(newName)); |
| Type copyType= ASTNodes.copySubtree(ast, fieldType); |
| newSingleVariableDeclaration.setType(copyType); |
| |
| FieldAccess fieldAccess= ast.newFieldAccess(); |
| fieldAccess.setName(ast.newSimpleName(variableName)); |
| fieldAccess.setExpression(ast.newThisExpression()); |
| |
| Assignment assignment= ast.newAssignment(); |
| assignment.setLeftHandSide(fieldAccess); |
| assignment.setOperator(Assignment.Operator.ASSIGN); |
| assignment.setRightHandSide(ast.newSimpleName(newName)); |
| ExpressionStatement statement= ast.newExpressionStatement(assignment); |
| |
| rewrite.getListRewrite(methodDeclaration, MethodDeclaration.PARAMETERS_PROPERTY).insertLast(newSingleVariableDeclaration, null); |
| Block body= methodDeclaration.getBody(); |
| // check if we call this(), then we can't add initialization here |
| if (!hasThisCall(body)) { |
| List<ASTNode> decls= ((AbstractTypeDeclaration) methodDeclaration.getParent()).bodyDeclarations(); |
| List<String> finalFieldList= getFinalFieldList(decls); |
| int insertIndex= 0; |
| if (finalFieldList.size() > 1) { |
| int findFirstFinalFieldReferenceIndex= findFirstFinalFieldReferenceIndex(body.statements(), variableName); |
| int findFinalFieldInsertIndex= findFinalFieldAssignmentInsertIndex(body.statements(), variableName, finalFieldList); |
| int index= findFirstFinalFieldReferenceIndex == -1 ? findFinalFieldInsertIndex : findFirstFinalFieldReferenceIndex; |
| insertIndex= Math.min(body.statements().size(), Math.min(findFinalFieldInsertIndex, index)); |
| } |
| rewrite.getListRewrite(body, Block.STATEMENTS_PROPERTY).insertAt(statement, insertIndex, null); |
| setEndPosition(rewrite.track(assignment)); // set cursor after expression statement |
| } |
| return rewrite; |
| } |
| |
| private String[] collectParameterNames(MethodDeclaration methodDeclaration) { |
| final List<String> names= new ArrayList<>(); |
| |
| for (Object element : methodDeclaration.parameters()) { |
| SingleVariableDeclaration svd= (SingleVariableDeclaration) element; |
| names.add(svd.getName().getIdentifier()); |
| } |
| ASTVisitor v = new ASTVisitor() { |
| @Override |
| public boolean visit(VariableDeclarationFragment node) { |
| names.add(node.getName().getIdentifier()); |
| return super.visit(node); |
| } |
| }; |
| methodDeclaration.accept(v); |
| return names.toArray(new String[names.size()]); |
| } |
| |
| private ASTRewrite doInitFieldInConstructor() { |
| String variableName= fProblem.getProblemArguments()[0]; |
| FieldDeclaration field= getFieldDeclaration(variableName); |
| if (field == null) { |
| return null; |
| } |
| AST ast= field.getAST(); |
| |
| FieldAccess fieldAccess= ast.newFieldAccess(); |
| fieldAccess.setName(ast.newSimpleName(variableName)); |
| fieldAccess.setExpression(ast.newThisExpression()); |
| |
| Assignment assignment= ast.newAssignment(); |
| assignment.setLeftHandSide(fieldAccess); |
| assignment.setOperator(Assignment.Operator.ASSIGN); |
| |
| Type fieldType= field.getType(); |
| if (fieldType.isPrimitiveType()) { |
| assignment.setRightHandSide(ast.newNumberLiteral()); |
| } else if ("String".equals(fieldType.toString())) { //$NON-NLS-1$ |
| assignment.setRightHandSide(ast.newStringLiteral()); |
| } else { |
| if (hasDefaultConstructor(fieldType.resolveBinding())) { |
| ClassInstanceCreation cic= ast.newClassInstanceCreation(); |
| cic.setType(ast.newSimpleType(ast.newName(fieldType.toString()))); |
| assignment.setRightHandSide(cic); |
| } else { |
| assignment.setRightHandSide(ast.newNullLiteral()); |
| } |
| } |
| ExpressionStatement statement= ast.newExpressionStatement(assignment); |
| |
| ASTRewrite rewrite= ASTRewrite.create(ast); |
| // find all constructors (methods with same name as the type name) |
| ConstructorVisitor cv= new ConstructorVisitor(((AbstractTypeDeclaration) field.getParent()).getName().toString()); |
| fAstNode.getRoot().accept(cv); |
| |
| for (MethodDeclaration md : cv.getNodes()) { |
| Block body= md.getBody(); |
| // check if we call this(), then we can't add initialization here |
| if (!hasThisCall(body)) { |
| if (hasFieldInitialization(body, variableName)) { |
| continue; |
| } |
| List<ASTNode> decls= ((AbstractTypeDeclaration) md.getParent()).bodyDeclarations(); |
| List<String> finalFieldList= getFinalFieldList(decls); |
| int insertIndex= 0; |
| if (finalFieldList.size() > 1) { |
| int findFirstFinalFieldReferenceIndex= findFirstFinalFieldReferenceIndex(body.statements(), variableName); |
| int findFinalFieldInsertIndex= findFinalFieldAssignmentInsertIndex(body.statements(), variableName, finalFieldList); |
| int index= findFirstFinalFieldReferenceIndex == -1 ? findFinalFieldInsertIndex : findFirstFinalFieldReferenceIndex; |
| insertIndex= Math.min(body.statements().size(), Math.min(findFinalFieldInsertIndex, index)); |
| } |
| rewrite.getListRewrite(body, Block.STATEMENTS_PROPERTY).insertAt(statement, insertIndex, null); |
| setEndPosition(rewrite.track(assignment)); // set cursor after expression statement |
| } |
| } |
| return rewrite; |
| } |
| |
| private boolean hasFieldInitialization(Block body, final String variableName) { |
| boolean[] hasInit= new boolean[1]; |
| ASTVisitor v= new ASTVisitor() { |
| @Override |
| public boolean visit(SimpleName node) { |
| if (!node.getIdentifier().equals(variableName)) { |
| return true; |
| } |
| ASTNode assignNode= ASTNodes.getFirstAncestorOrNull(node, Assignment.class); |
| if (assignNode != null) { |
| Expression lhs= ((Assignment) assignNode).getLeftHandSide(); |
| IBinding resolveBinding= node.resolveBinding(); |
| if (resolveBinding != null && ((IVariableBinding) resolveBinding).isField()) { |
| int nodeType= lhs.getNodeType(); |
| if (nodeType == ASTNode.SIMPLE_NAME) { |
| String name= ((SimpleName) lhs).getIdentifier(); |
| if (variableName.equals(name)) { |
| hasInit[0]= true; |
| return false; |
| } |
| } else if (nodeType == ASTNode.FIELD_ACCESS) { |
| String name= ((FieldAccess) lhs).getName().getIdentifier(); |
| if (variableName.equals(name)) { |
| hasInit[0]= true; |
| return false; |
| } |
| } |
| } |
| } |
| return true; |
| } |
| }; |
| body.accept(v); |
| return hasInit[0]; |
| } |
| |
| private List<String> getFinalFieldList(List<ASTNode> fieldDeclarations) { |
| List<String> list= new ArrayList<>(); |
| for (ASTNode astNode : fieldDeclarations) { |
| if (astNode instanceof FieldDeclaration) { |
| int modifiers= ((FieldDeclaration) astNode).getModifiers(); |
| if (!Modifier.isFinal(modifiers)) { |
| continue; |
| } |
| for (Object object : ((FieldDeclaration) astNode).fragments()) { |
| list.add(((VariableDeclarationFragment) object).getName().getIdentifier()); |
| } |
| } |
| } |
| return list; |
| } |
| |
| /* |
| * Find insertion index in statements based on declaration order. |
| */ |
| private int findFinalFieldAssignmentInsertIndex(List<ASTNode> astNodes, String variableName, List<String> finalFieldList) { |
| int index= 0; |
| int fieldIndex= 0; |
| int findFinalFieldDeclarationIndex= finalFieldList.indexOf(variableName); |
| String[] fieldAccess= new String[1]; |
| |
| for (ASTNode astNode : astNodes) { |
| fieldAccess[0]= null; |
| |
| ASTVisitor v= new ASTVisitor() { |
| @Override |
| public boolean visit(FieldAccess node) { |
| fieldAccess[0]= node.getName().getIdentifier(); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(SimpleName node) { |
| ASTNode assignNode= ASTNodes.getFirstAncestorOrNull(node, Assignment.class); |
| if (assignNode != null) { |
| IBinding resolveBinding= node.resolveBinding(); |
| if (resolveBinding instanceof IVariableBinding |
| && ((IVariableBinding) resolveBinding).isField() |
| && resolveBinding.getKind() == IBinding.VARIABLE |
| && finalFieldList.contains(node.getIdentifier())) { |
| fieldAccess[0]= node.getIdentifier(); |
| return false; |
| } |
| } |
| return true; |
| } |
| }; |
| astNode.accept(v); |
| if (fieldAccess[0] == null) { |
| index++; |
| continue; |
| } |
| String fieldId= fieldAccess[0]; |
| int indexOfField= finalFieldList.indexOf(fieldId); |
| fieldIndex= index; |
| if (indexOfField > findFinalFieldDeclarationIndex) { |
| return fieldIndex; |
| } |
| fieldIndex++; |
| index++; |
| } |
| return fieldIndex; |
| } |
| |
| private int findFirstFinalFieldReferenceIndex(List<ASTNode> astNodes, String variableName) { |
| int index= 0; |
| String[] fieldAccess= new String[1]; |
| |
| for (ASTNode astNode : astNodes) { |
| fieldAccess[0]= null; |
| |
| ASTVisitor v= new ASTVisitor() { |
| @Override |
| public boolean visit(FieldAccess node) { |
| fieldAccess[0]= node.getName().getIdentifier(); |
| return false; |
| } |
| |
| @Override |
| public boolean visit(SimpleName node) { |
| IBinding resolveBinding= node.resolveBinding(); |
| if (resolveBinding != null && resolveBinding.getKind() == IBinding.VARIABLE) { |
| if (((IVariableBinding) resolveBinding).isField()) { |
| fieldAccess[0]= node.getIdentifier(); |
| return false; |
| } |
| } |
| return true; |
| } |
| }; |
| astNode.accept(v); |
| if (fieldAccess[0] != null && fieldAccess[0].equals(variableName)) { |
| return index; |
| } |
| index++; |
| } |
| return -1; |
| } |
| |
| private boolean hasThisCall(Block body) { |
| for (Object object : body.statements()) { |
| if (((ASTNode) object).getNodeType() == ASTNode.CONSTRUCTOR_INVOCATION) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| private boolean hasDefaultConstructor(ITypeBinding type) { |
| for (IMethodBinding mb : type.getDeclaredMethods()) { |
| String key= mb.getKey(); |
| if (key.contains(";.()V")) { //$NON-NLS-1$ |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| private boolean hasDefaultConstructor() { |
| return hasDefaultConstructor(fVariableBinding.getType()); |
| } |
| |
| private FieldDeclaration getFieldDeclaration(String name) { |
| FieldVisitor fieldVisitor= new FieldVisitor(); |
| fAstNode.getRoot().accept(fieldVisitor); |
| |
| for (FieldDeclaration f : fieldVisitor.getNodes()) { |
| for (Object object : f.fragments()) { |
| VariableDeclarationFragment fragment= (VariableDeclarationFragment) object; |
| if (fragment.getName().getIdentifier().equals(name)) { |
| return f; |
| } |
| } |
| } |
| return null; |
| } |
| |
| private SingleVariableDeclaration getRecordComponentDeclaration(String name) { |
| RecordComponentVisitor recordComponentVisitor= new RecordComponentVisitor(); |
| fAstNode.getRoot().accept(recordComponentVisitor); |
| |
| for (SingleVariableDeclaration f : recordComponentVisitor.getNodes()) { |
| if (f.getName().getIdentifier().equals(name)) { |
| return f; |
| } |
| } |
| return null; |
| } |
| |
| private static final class FieldVisitor extends ASTVisitor { |
| private final List<FieldDeclaration> fNodes= new ArrayList<>(); |
| |
| public FieldVisitor() { |
| } |
| |
| @Override |
| public boolean visit(FieldDeclaration node) { |
| fNodes.add(node); |
| return true; |
| } |
| |
| public List<FieldDeclaration> getNodes() { |
| return fNodes; |
| } |
| } |
| |
| private static final class ConstructorVisitor extends ASTVisitor { |
| private final List<MethodDeclaration> fNodes= new ArrayList<>(); |
| |
| private String fTypeName; |
| |
| public ConstructorVisitor(String typeName) { |
| fTypeName= typeName; |
| } |
| |
| @Override |
| public boolean visit(MethodDeclaration node) { |
| if (node.getName().toString().equals(fTypeName)) { |
| fNodes.add(node); |
| } |
| return true; |
| } |
| |
| public List<MethodDeclaration> getNodes() { |
| return fNodes; |
| } |
| } |
| |
| private static final class RecordComponentVisitor extends ASTVisitor { |
| private final List<SingleVariableDeclaration> fNodes= new ArrayList<>(); |
| |
| public RecordComponentVisitor() { |
| } |
| |
| @Override |
| public boolean visit(RecordDeclaration node) { |
| List<SingleVariableDeclaration> decl= node.recordComponents(); |
| if (decl != null) |
| fNodes.addAll(decl); |
| return true; |
| } |
| |
| public List<SingleVariableDeclaration> getNodes() { |
| return fNodes; |
| } |
| } |
| } |