/******************************************************************************* * Copyright (c) 2016 Till Brychcy and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Till Brychcy - initial API and implementation *******************************************************************************/ package org.eclipse.jdt.internal.ui.text.correction.proposals; 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.Annotation; import org.eclipse.jdt.core.dom.Block; import org.eclipse.jdt.core.dom.ChildListPropertyDescriptor; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.IVariableBinding; import org.eclipse.jdt.core.dom.SingleVariableDeclaration; import org.eclipse.jdt.core.dom.Type; import org.eclipse.jdt.core.dom.VariableDeclarationExpression; import org.eclipse.jdt.core.dom.VariableDeclarationFragment; import org.eclipse.jdt.core.dom.VariableDeclarationStatement; import org.eclipse.jdt.core.dom.rewrite.ASTRewrite; import org.eclipse.jdt.core.dom.rewrite.ImportRewrite; import org.eclipse.jdt.core.dom.rewrite.ImportRewrite.ImportRewriteContext; import org.eclipse.jdt.core.dom.rewrite.ListRewrite; import org.eclipse.jdt.internal.corext.codemanipulation.ContextSensitiveImportRewriteContext; import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory; import org.eclipse.jdt.internal.corext.util.Messages; import org.eclipse.jdt.ui.text.java.correction.ASTRewriteCorrectionProposal; import org.eclipse.jdt.internal.ui.JavaPluginImages; import org.eclipse.jdt.internal.ui.text.correction.CorrectionMessages; import org.eclipse.jdt.internal.core.manipulation.util.BasicElementLabels; public class MakeLocalVariableNonNullProposal extends ASTRewriteCorrectionProposal { private final IVariableBinding fBinding; private final CompilationUnit fAstRoot; private final String fNonNullAnnotationName; public MakeLocalVariableNonNullProposal(ICompilationUnit targetCU, IVariableBinding varBinding, CompilationUnit astRoot, int relevance, String nonNullAnnotationName) { super("", targetCU, null, relevance, JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE)); //$NON-NLS-1$ fNonNullAnnotationName= nonNullAnnotationName; fBinding= varBinding; fAstRoot= astRoot; String annotationNameLabel= fNonNullAnnotationName; int lastDot= fNonNullAnnotationName.lastIndexOf('.'); if (lastDot != -1) annotationNameLabel= fNonNullAnnotationName.substring(lastDot + 1); annotationNameLabel= BasicElementLabels.getJavaElementName(annotationNameLabel); String[] args= { BasicElementLabels.getJavaElementName(varBinding.getName()), annotationNameLabel }; setDisplayName(Messages.format(CorrectionMessages.NullAnnotationsCorrectionProcessor_change_local_variable_to_nonNull, args)); } @Override protected ASTRewrite getRewrite() throws CoreException { ASTNode declNode= fAstRoot.findDeclaringNode(fBinding); if (declNode != null) { AST ast= declNode.getAST(); ASTRewrite rewrite= ASTRewrite.create(ast); ImportRewrite imports= createImportRewrite(fAstRoot); ImportRewriteContext context= new ContextSensitiveImportRewriteContext(fAstRoot, declNode.getStartPosition(), imports); String nonNullType= imports.addImport(fNonNullAnnotationName, context); if (declNode instanceof VariableDeclarationFragment) { ASTNode parent= declNode.getParent(); if (parent instanceof VariableDeclarationStatement) { VariableDeclarationStatement varDecl= (VariableDeclarationStatement) parent; if (varDecl.fragments().size() > 1 && (varDecl.getParent() instanceof Block)) { // split VariableDeclarationFragment placeholder= (VariableDeclarationFragment) rewrite.createMoveTarget(declNode); VariableDeclarationStatement newStat= ast.newVariableDeclarationStatement(placeholder); newStat.setType((Type) rewrite.createCopyTarget(varDecl.getType())); newStat.modifiers().addAll(ASTNodeFactory.newModifiers(ast, varDecl.getModifiers())); addNullAnnotation(newStat, VariableDeclarationStatement.MODIFIERS2_PROPERTY, rewrite, nonNullType, ast); ListRewrite listRewrite= rewrite.getListRewrite(varDecl.getParent(), Block.STATEMENTS_PROPERTY); if (varDecl.fragments().indexOf(declNode) == 0) { // if it as the first in the list-> insert before listRewrite.insertBefore(newStat, parent, null); } else { listRewrite.insertAfter(newStat, parent, null); } } else { addNullAnnotation(varDecl, VariableDeclarationStatement.MODIFIERS2_PROPERTY, rewrite, nonNullType, ast); } } else if (parent instanceof VariableDeclarationExpression) { VariableDeclarationExpression varDecl= (VariableDeclarationExpression) parent; addNullAnnotation(varDecl, VariableDeclarationExpression.MODIFIERS2_PROPERTY, rewrite, nonNullType, ast); } } else if (declNode instanceof SingleVariableDeclaration) { SingleVariableDeclaration varDecl= (SingleVariableDeclaration) declNode; addNullAnnotation(varDecl, SingleVariableDeclaration.MODIFIERS2_PROPERTY, rewrite, nonNullType, ast); } return rewrite; } return null; } private void addNullAnnotation(ASTNode varDecl, ChildListPropertyDescriptor modifiers2Property, ASTRewrite rewrite, String nonNullType, AST ast) { ListRewrite listRewrite= rewrite.getListRewrite(varDecl, modifiers2Property); Annotation newAnnotation= ast.newMarkerAnnotation(); newAnnotation.setTypeName(ast.newName(nonNullType)); listRewrite.insertLast(newAnnotation, null); // null annotation is last modifier, directly preceding the type } }