1 /*******************************************************************************
2  * Copyright (c) 2000, 2019 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *     Microsoft Corporation - copied to jdt.core.manipulation
14  *******************************************************************************/
15 package org.eclipse.jdt.internal.corext.refactoring.structure;
16 
17 import java.util.HashSet;
18 import java.util.Set;
19 
20 import org.eclipse.ltk.core.refactoring.RefactoringStatus;
21 
22 import org.eclipse.jdt.core.dom.AST;
23 import org.eclipse.jdt.core.dom.ASTNode;
24 import org.eclipse.jdt.core.dom.ASTVisitor;
25 import org.eclipse.jdt.core.dom.Expression;
26 import org.eclipse.jdt.core.dom.FieldAccess;
27 import org.eclipse.jdt.core.dom.IBinding;
28 import org.eclipse.jdt.core.dom.IPackageBinding;
29 import org.eclipse.jdt.core.dom.ITypeBinding;
30 import org.eclipse.jdt.core.dom.MemberRef;
31 import org.eclipse.jdt.core.dom.MethodInvocation;
32 import org.eclipse.jdt.core.dom.MethodRef;
33 import org.eclipse.jdt.core.dom.Name;
34 import org.eclipse.jdt.core.dom.QualifiedName;
35 import org.eclipse.jdt.core.dom.SimpleName;
36 import org.eclipse.jdt.core.dom.Type;
37 import org.eclipse.jdt.core.dom.rewrite.ImportRewrite.ImportRewriteContext;
38 
39 import org.eclipse.jdt.internal.corext.codemanipulation.ContextSensitiveImportRewriteContext;
40 import org.eclipse.jdt.internal.corext.dom.ASTFlattener;
41 import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory;
42 import org.eclipse.jdt.internal.corext.dom.ASTNodes;
43 import org.eclipse.jdt.internal.corext.dom.Bindings;
44 import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
45 import org.eclipse.jdt.internal.corext.refactoring.util.JavaStatusContext;
46 
47 /* package */ class MoveStaticMemberAnalyzer extends ASTVisitor {
48 
49 	protected RefactoringStatus fStatus;
50 
51 	protected ITypeBinding fSource;
52 	protected ITypeBinding fTarget;
53 	protected CompilationUnitRewrite fCuRewrite;
54 	protected IBinding[] fMembers;
55 
56 	protected boolean fNeedsImport;
57 
58 	protected Set<SimpleName> fProcessed;
59 
60 	protected static final String REFERENCE_UPDATE= RefactoringCoreMessages.MoveMembersRefactoring_referenceUpdate;
61 
MoveStaticMemberAnalyzer(CompilationUnitRewrite cuRewrite, IBinding[] members, ITypeBinding source, ITypeBinding target)62 	public MoveStaticMemberAnalyzer(CompilationUnitRewrite cuRewrite, IBinding[] members, ITypeBinding source, ITypeBinding target) {
63 		super(true);
64 		fStatus= new RefactoringStatus();
65 		fCuRewrite= cuRewrite;
66 		fMembers= members;
67 		fSource= source;
68 		fTarget= target;
69 		fProcessed= new HashSet<>();
70 	}
71 
getStatus()72 	public RefactoringStatus getStatus() {
73 		return fStatus;
74 	}
75 
isProcessed(ASTNode node)76 	protected boolean isProcessed(ASTNode node) {
77 		return fProcessed.contains(node);
78 	}
79 
rewrite(SimpleName node, ITypeBinding type)80 	protected void rewrite(SimpleName node, ITypeBinding type) {
81 		AST ast= node.getAST();
82 		ImportRewriteContext context= new ContextSensitiveImportRewriteContext(node, fCuRewrite.getImportRewrite());
83 		Type result= fCuRewrite.getImportRewrite().addImport(type, fCuRewrite.getAST(), context);
84 		fCuRewrite.getImportRemover().registerAddedImport(type.getQualifiedName());
85 		Name dummy= ASTNodeFactory.newName(fCuRewrite.getAST(), ASTFlattener.asString(result));
86 		QualifiedName name= ast.newQualifiedName(dummy, ast.newSimpleName(node.getIdentifier()));
87 		fCuRewrite.getASTRewrite().replace(node, name, fCuRewrite.createGroupDescription(REFERENCE_UPDATE));
88 		fCuRewrite.getImportRemover().registerRemovedNode(node);
89 		fProcessed.add(node);
90 		fNeedsImport= true;
91 	}
92 
rewrite(QualifiedName node, ITypeBinding type)93 	protected void rewrite(QualifiedName node, ITypeBinding type) {
94 		rewriteName(node.getQualifier(), type);
95 		fProcessed.add(node.getName());
96 	}
97 
rewrite(FieldAccess node, ITypeBinding type)98 	protected void rewrite(FieldAccess node, ITypeBinding type) {
99 		Expression exp= node.getExpression();
100 		if (exp == null) {
101 			ImportRewriteContext context= new ContextSensitiveImportRewriteContext(node, fCuRewrite.getImportRewrite());
102 			Type result= fCuRewrite.getImportRewrite().addImport(type, fCuRewrite.getAST(), context);
103 			fCuRewrite.getImportRemover().registerAddedImport(type.getQualifiedName());
104 			exp= ASTNodeFactory.newName(fCuRewrite.getAST(), ASTFlattener.asString(result));
105 			fCuRewrite.getASTRewrite().set(node, FieldAccess.EXPRESSION_PROPERTY, exp,  fCuRewrite.createGroupDescription(REFERENCE_UPDATE));
106 			fNeedsImport= true;
107 		} else if (exp instanceof Name) {
108 			rewriteName((Name)exp, type);
109 		} else {
110 			rewriteExpression(node, exp, type);
111 		}
112 		fProcessed.add(node.getName());
113 	}
114 
rewrite(MethodInvocation node, ITypeBinding type)115 	protected void rewrite(MethodInvocation node, ITypeBinding type) {
116 		Expression exp= node.getExpression();
117 		if (exp == null) {
118 			ImportRewriteContext context= new ContextSensitiveImportRewriteContext(node, fCuRewrite.getImportRewrite());
119 			Type result= fCuRewrite.getImportRewrite().addImport(type, fCuRewrite.getAST(), context);
120 			fCuRewrite.getImportRemover().registerAddedImport(type.getQualifiedName());
121 			exp= ASTNodeFactory.newName(fCuRewrite.getAST(), ASTFlattener.asString(result));
122 			fCuRewrite.getASTRewrite().set(node, MethodInvocation.EXPRESSION_PROPERTY, exp, fCuRewrite.createGroupDescription(REFERENCE_UPDATE));
123 			fNeedsImport= true;
124 		} else if (exp instanceof Name) {
125 			rewriteName((Name)exp, type);
126 		} else {
127 			rewriteExpression(node, exp, type);
128 		}
129 		fProcessed.add(node.getName());
130 	}
131 
rewrite(MemberRef node, ITypeBinding type)132 	protected void rewrite(MemberRef node, ITypeBinding type) {
133 		Name qualifier= node.getQualifier();
134 		if (qualifier == null) {
135 			ImportRewriteContext context= new ContextSensitiveImportRewriteContext(node, fCuRewrite.getImportRewrite());
136 			Type result= fCuRewrite.getImportRewrite().addImport(type, fCuRewrite.getAST(), context);
137 			fCuRewrite.getImportRemover().registerAddedImport(type.getQualifiedName());
138 			qualifier= ASTNodeFactory.newName(fCuRewrite.getAST(), ASTFlattener.asString(result));
139 			fCuRewrite.getASTRewrite().set(node, MemberRef.QUALIFIER_PROPERTY, qualifier, fCuRewrite.createGroupDescription(REFERENCE_UPDATE));
140 			fNeedsImport= true;
141 		} else {
142 			rewriteName(qualifier, type);
143 		}
144 		fProcessed.add(node.getName());
145 	}
146 
rewrite(MethodRef node, ITypeBinding type)147 	protected void rewrite(MethodRef node, ITypeBinding type) {
148 		Name qualifier= node.getQualifier();
149 		if (qualifier == null) {
150 			ImportRewriteContext context= new ContextSensitiveImportRewriteContext(node, fCuRewrite.getImportRewrite());
151 			Type result= fCuRewrite.getImportRewrite().addImport(type, fCuRewrite.getAST(), context);
152 			fCuRewrite.getImportRemover().registerAddedImport(type.getQualifiedName());
153 			qualifier= ASTNodeFactory.newName(fCuRewrite.getAST(), ASTFlattener.asString(result));
154 			fCuRewrite.getASTRewrite().set(node, MethodRef.QUALIFIER_PROPERTY, qualifier, fCuRewrite.createGroupDescription(REFERENCE_UPDATE));
155 			fNeedsImport= true;
156 		} else {
157 			rewriteName(qualifier, type);
158 		}
159 		fProcessed.add(node.getName());
160 	}
161 
rewriteName(Name name, ITypeBinding type)162 	private void rewriteName(Name name, ITypeBinding type) {
163 		AST creator= name.getAST();
164 		boolean fullyQualified= false;
165 		if (name instanceof QualifiedName) {
166 			SimpleName left= ASTNodes.getLeftMostSimpleName(name);
167 			if (left.resolveBinding() instanceof IPackageBinding)
168 				fullyQualified= true;
169 		}
170 		if (fullyQualified) {
171 			fCuRewrite.getASTRewrite().replace(
172 				name,
173 				ASTNodeFactory.newName(creator, type.getQualifiedName()),
174 				fCuRewrite.createGroupDescription(REFERENCE_UPDATE));
175 			fCuRewrite.getImportRemover().registerRemovedNode(name);
176 		} else {
177 			ImportRewriteContext context= new ContextSensitiveImportRewriteContext(name, fCuRewrite.getImportRewrite());
178 			Type result= fCuRewrite.getImportRewrite().addImport(type, fCuRewrite.getAST(), context);
179 			fCuRewrite.getImportRemover().registerAddedImport(type.getQualifiedName());
180 			Name n= ASTNodeFactory.newName(fCuRewrite.getAST(), ASTFlattener.asString(result));
181 			fCuRewrite.getASTRewrite().replace(
182 				name,
183 				n,
184 				fCuRewrite.createGroupDescription(REFERENCE_UPDATE));
185 			fCuRewrite.getImportRemover().registerRemovedNode(name);
186 			fNeedsImport= true;
187 		}
188 	}
189 
rewriteExpression(ASTNode node, Expression exp, ITypeBinding type)190 	private void rewriteExpression(ASTNode node, Expression exp, ITypeBinding type) {
191 		ImportRewriteContext context= new ContextSensitiveImportRewriteContext(exp, fCuRewrite.getImportRewrite());
192 		Type typeNode= fCuRewrite.getImportRewrite().addImport(type, fCuRewrite.getAST(), context);
193 		fCuRewrite.getASTRewrite().replace(exp, typeNode, fCuRewrite.createGroupDescription(REFERENCE_UPDATE));
194 		fCuRewrite.getImportRemover().registerAddedImport(type.getQualifiedName());
195 		fCuRewrite.getImportRemover().registerRemovedNode(exp);
196 		fNeedsImport= true;
197 		nonStaticAccess(node);
198 	}
199 
nonStaticAccess(ASTNode node)200 	protected void nonStaticAccess(ASTNode node) {
201 		fStatus.addWarning(RefactoringCoreMessages.MoveStaticMemberAnalyzer_nonStatic,
202 			JavaStatusContext.create(fCuRewrite.getCu(), node));
203 	}
204 
isStaticAccess(Expression exp, ITypeBinding type)205 	protected boolean isStaticAccess(Expression exp, ITypeBinding type) {
206 		if (!(exp instanceof Name))
207 			return false;
208 		return Bindings.equals(type, ((Name)exp).resolveBinding());
209 	}
210 
isMovedMember(IBinding binding)211 	protected boolean isMovedMember(IBinding binding) {
212 		if (binding == null)
213 			return false;
214 		for (IBinding member : fMembers) {
215 			if (Bindings.equalDeclarations(member, binding))
216 				return true;
217 		}
218 		return false;
219 	}
220 }
221