KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > corext > refactoring > TypeContextChecker


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11
12 package org.eclipse.jdt.internal.corext.refactoring;
13
14 import java.util.ArrayList JavaDoc;
15 import java.util.Collections JavaDoc;
16 import java.util.HashMap JavaDoc;
17 import java.util.Iterator JavaDoc;
18 import java.util.List JavaDoc;
19 import java.util.Map JavaDoc;
20
21 import org.eclipse.core.runtime.Assert;
22 import org.eclipse.core.runtime.CoreException;
23 import org.eclipse.core.runtime.IProgressMonitor;
24 import org.eclipse.core.runtime.NullProgressMonitor;
25
26 import org.eclipse.jface.text.BadLocationException;
27 import org.eclipse.jface.text.IDocument;
28
29 import org.eclipse.ltk.core.refactoring.RefactoringStatus;
30
31 import org.eclipse.jdt.core.Flags;
32 import org.eclipse.jdt.core.ICompilationUnit;
33 import org.eclipse.jdt.core.IJavaProject;
34 import org.eclipse.jdt.core.IMethod;
35 import org.eclipse.jdt.core.IPackageFragment;
36 import org.eclipse.jdt.core.ISourceRange;
37 import org.eclipse.jdt.core.IType;
38 import org.eclipse.jdt.core.ITypeParameter;
39 import org.eclipse.jdt.core.JavaModelException;
40 import org.eclipse.jdt.core.WorkingCopyOwner;
41 import org.eclipse.jdt.core.compiler.IProblem;
42 import org.eclipse.jdt.core.dom.AST;
43 import org.eclipse.jdt.core.dom.ASTNode;
44 import org.eclipse.jdt.core.dom.ASTParser;
45 import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
46 import org.eclipse.jdt.core.dom.AnnotationTypeDeclaration;
47 import org.eclipse.jdt.core.dom.AnnotationTypeMemberDeclaration;
48 import org.eclipse.jdt.core.dom.AnonymousClassDeclaration;
49 import org.eclipse.jdt.core.dom.ArrayType;
50 import org.eclipse.jdt.core.dom.Block;
51 import org.eclipse.jdt.core.dom.BodyDeclaration;
52 import org.eclipse.jdt.core.dom.ClassInstanceCreation;
53 import org.eclipse.jdt.core.dom.CompilationUnit;
54 import org.eclipse.jdt.core.dom.EnumDeclaration;
55 import org.eclipse.jdt.core.dom.IExtendedModifier;
56 import org.eclipse.jdt.core.dom.ITypeBinding;
57 import org.eclipse.jdt.core.dom.ImportDeclaration;
58 import org.eclipse.jdt.core.dom.MethodDeclaration;
59 import org.eclipse.jdt.core.dom.Modifier;
60 import org.eclipse.jdt.core.dom.Name;
61 import org.eclipse.jdt.core.dom.PackageDeclaration;
62 import org.eclipse.jdt.core.dom.PrimitiveType;
63 import org.eclipse.jdt.core.dom.QualifiedName;
64 import org.eclipse.jdt.core.dom.QualifiedType;
65 import org.eclipse.jdt.core.dom.SimpleName;
66 import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
67 import org.eclipse.jdt.core.dom.Type;
68 import org.eclipse.jdt.core.dom.TypeDeclaration;
69 import org.eclipse.jdt.core.dom.TypeParameter;
70 import org.eclipse.jdt.core.search.IJavaSearchConstants;
71 import org.eclipse.jdt.core.search.IJavaSearchScope;
72 import org.eclipse.jdt.core.search.SearchEngine;
73 import org.eclipse.jdt.core.search.SearchPattern;
74 import org.eclipse.jdt.core.search.TypeNameMatch;
75
76 import org.eclipse.jdt.internal.corext.dom.ASTFlattener;
77 import org.eclipse.jdt.internal.corext.dom.ASTNodes;
78 import org.eclipse.jdt.internal.corext.dom.HierarchicalASTVisitor;
79 import org.eclipse.jdt.internal.corext.dom.NodeFinder;
80 import org.eclipse.jdt.internal.corext.dom.Selection;
81 import org.eclipse.jdt.internal.corext.dom.SelectionAnalyzer;
82 import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser;
83 import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringFileBuffers;
84 import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
85 import org.eclipse.jdt.internal.corext.util.Messages;
86 import org.eclipse.jdt.internal.corext.util.TypeNameMatchCollector;
87
88 import org.eclipse.jdt.internal.ui.JavaPlugin;
89 import org.eclipse.jdt.internal.ui.refactoring.contentassist.JavaTypeCompletionProcessor;
90
91 public class TypeContextChecker {
92
93     public interface IProblemVerifier {
94
95         boolean isError(IProblem problem, ASTNode node);
96
97     }
98
99     private static class MethodTypesChecker {
100
101         private static final String JavaDoc METHOD_NAME= "__$$__"; //$NON-NLS-1$
102

103         private final IMethod fMethod;
104         private final StubTypeContext fStubTypeContext;
105         private final List JavaDoc/*<ParameterInfo>*/ fParameterInfos;
106         private final ReturnTypeInfo fReturnTypeInfo;
107
108         private final IProblemVerifier fProblemVerifier;
109
110         public MethodTypesChecker(IMethod method, StubTypeContext stubTypeContext, List JavaDoc/*<ParameterInfo>*/ parameterInfos, ReturnTypeInfo returnTypeInfo, IProblemVerifier problemVerifier) {
111             fMethod= method;
112             fStubTypeContext= stubTypeContext;
113             fParameterInfos= parameterInfos;
114             fReturnTypeInfo= returnTypeInfo;
115             fProblemVerifier= problemVerifier;
116         }
117         
118         public RefactoringStatus[] checkAndResolveMethodTypes() throws CoreException {
119             RefactoringStatus[] results= new MethodTypesSyntaxChecker(fMethod, fParameterInfos, fReturnTypeInfo).checkSyntax();
120             for (int i= 0; i < results.length; i++)
121                 if (results[i] != null && results[i].hasFatalError())
122                     return results;
123             
124             int parameterCount= fParameterInfos.size();
125             String JavaDoc[] types= new String JavaDoc[parameterCount + 1];
126             for (int i= 0; i < parameterCount; i++)
127                 types[i]= ParameterInfo.stripEllipsis(((ParameterInfo) fParameterInfos.get(i)).getNewTypeName());
128             types[parameterCount]= fReturnTypeInfo.getNewTypeName();
129             RefactoringStatus[] semanticsResults= new RefactoringStatus[parameterCount + 1];
130             ITypeBinding[] typeBindings= resolveBindings(types, semanticsResults, true);
131             
132             boolean needsSecondPass= false;
133             for (int i= 0; i < types.length; i++)
134                 if (typeBindings[i] == null || ! semanticsResults[i].isOK())
135                     needsSecondPass= true;
136             
137             RefactoringStatus[] semanticsResults2= new RefactoringStatus[parameterCount + 1];
138             if (needsSecondPass)
139                 typeBindings= resolveBindings(types, semanticsResults2, false);
140             
141             for (int i= 0; i < fParameterInfos.size(); i++) {
142                 ParameterInfo parameterInfo= (ParameterInfo) fParameterInfos.get(i);
143                 if (parameterInfo.getOldTypeBinding() != null && ! parameterInfo.isTypeNameChanged()) {
144                     parameterInfo.setNewTypeBinding(parameterInfo.getOldTypeBinding());
145                 } else {
146                     parameterInfo.setNewTypeBinding(typeBindings[i]);
147                     if (typeBindings[i] == null || (needsSecondPass && ! semanticsResults2[i].isOK())) {
148                         if (results[i] == null)
149                             results[i]= semanticsResults2[i];
150                         else
151                             results[i].merge(semanticsResults2[i]);
152                     }
153                 }
154             }
155             fReturnTypeInfo.setNewTypeBinding(typeBindings[fParameterInfos.size()]);
156             if (typeBindings[parameterCount] == null || (needsSecondPass && ! semanticsResults2[parameterCount].isOK())) {
157                 if (results[parameterCount] == null)
158                     results[parameterCount]= semanticsResults2[parameterCount];
159                 else
160                     results[parameterCount].merge(semanticsResults2[parameterCount]);
161             }
162             
163             return results;
164         }
165
166         private ITypeBinding[] resolveBindings(String JavaDoc[] types, RefactoringStatus[] results, boolean firstPass) throws CoreException {
167             //TODO: split types into parameterTypes and returnType
168
int parameterCount= types.length - 1;
169             ITypeBinding[] typeBindings= new ITypeBinding[types.length];
170             
171             StringBuffer JavaDoc cuString= new StringBuffer JavaDoc();
172             cuString.append(fStubTypeContext.getBeforeString());
173             int offsetBeforeMethodName= appendMethodDeclaration(cuString, types, parameterCount);
174             cuString.append(fStubTypeContext.getAfterString());
175             
176             // need a working copy to tell the parser where to resolve (package visible) types
177
ICompilationUnit wc= fMethod.getCompilationUnit().getWorkingCopy(new WorkingCopyOwner() {/*subclass*/}, new NullProgressMonitor());
178             try {
179                 wc.getBuffer().setContents(cuString.toString());
180                 CompilationUnit compilationUnit= new RefactoringASTParser(AST.JLS3).parse(wc, true);
181                 ASTNode method= NodeFinder.perform(compilationUnit, offsetBeforeMethodName, METHOD_NAME.length()).getParent();
182                 Type[] typeNodes= new Type[types.length];
183                 if (method instanceof MethodDeclaration) {
184                     MethodDeclaration methodDeclaration= (MethodDeclaration) method;
185                     typeNodes[parameterCount]= methodDeclaration.getReturnType2();
186                     List JavaDoc/*<SingleVariableDeclaration>*/ parameters= methodDeclaration.parameters();
187                     for (int i= 0; i < parameterCount; i++)
188                         typeNodes[i]= ((SingleVariableDeclaration) parameters.get(i)).getType();
189
190                 } else if (method instanceof AnnotationTypeMemberDeclaration) {
191                     typeNodes[0]= ((AnnotationTypeMemberDeclaration) method).getType();
192                 }
193
194                 for (int i= 0; i < types.length; i++) {
195                     Type type= typeNodes[i];
196                     if (type == null) {
197                         String JavaDoc msg= Messages.format(RefactoringCoreMessages.TypeContextChecker_couldNotResolveType, types[i]);
198                         results[i]= RefactoringStatus.createErrorStatus(msg);
199                         continue;
200                     }
201                     results[i]= new RefactoringStatus();
202                     IProblem[] problems= ASTNodes.getProblems(type, ASTNodes.NODE_ONLY, ASTNodes.PROBLEMS);
203                     if (problems.length > 0) {
204                         for (int p= 0; p < problems.length; p++)
205                             if (isError(problems[p], type))
206                                 results[i].addError(problems[p].getMessage());
207                     }
208                     typeBindings[i]= type.resolveBinding();
209                     typeBindings[i]= handleBug84585(typeBindings[i]);
210                     if (firstPass && typeBindings[i] == null)
211                         types[i]= qualifyTypes(type, results[i]);
212                 }
213                 return typeBindings;
214             } finally {
215                 wc.discardWorkingCopy();
216             }
217         }
218
219         private boolean isError(IProblem problem, Type type) {
220             if (fProblemVerifier != null)
221                 return fProblemVerifier.isError(problem, type);
222             return true;
223         }
224
225         private int appendMethodDeclaration(StringBuffer JavaDoc cuString, String JavaDoc[] types, int parameterCount) throws JavaModelException {
226             if (Flags.isStatic(fMethod.getFlags()))
227                 cuString.append("static "); //$NON-NLS-1$
228

229             ITypeParameter[] methodTypeParameters= fMethod.getTypeParameters();
230             if (methodTypeParameters.length != 0) {
231                 cuString.append('<');
232                 for (int i= 0; i < methodTypeParameters.length; i++) {
233                     ITypeParameter typeParameter= methodTypeParameters[i];
234                     if (i > 0)
235                         cuString.append(',');
236                     cuString.append(typeParameter.getElementName());
237                 }
238                 cuString.append("> "); //$NON-NLS-1$
239
}
240             
241             cuString.append(types[parameterCount]).append(' ');
242             int offsetBeforeMethodName= cuString.length();
243             cuString.append(METHOD_NAME).append('(');
244             for (int i= 0; i < parameterCount; i++) {
245                 if (i > 0)
246                     cuString.append(',');
247                 cuString.append(types[i]).append(" p").append(i); //$NON-NLS-1$
248
}
249             cuString.append(");"); //$NON-NLS-1$
250

251             return offsetBeforeMethodName;
252         }
253
254         private String JavaDoc qualifyTypes(Type type, final RefactoringStatus result) throws CoreException {
255             class NestedException extends RuntimeException JavaDoc {
256                 private static final long serialVersionUID= 1L;
257                 NestedException(CoreException e) {
258                     super(e);
259                 }
260             }
261             ASTFlattener flattener= new ASTFlattener() {
262                 public boolean visit(SimpleName node) {
263                     appendResolved(node.getIdentifier());
264                     return false;
265                 }
266                 public boolean visit(QualifiedName node) {
267                     appendResolved(node.getFullyQualifiedName());
268                     return false;
269                 }
270                 public boolean visit(QualifiedType node) {
271                     appendResolved(ASTNodes.asString(node));
272                     return false;
273                 }
274                 private void appendResolved(String JavaDoc typeName) {
275                     String JavaDoc resolvedType;
276                     try {
277                         resolvedType= resolveType(typeName, result, fMethod.getDeclaringType(), null);
278                     } catch (CoreException e) {
279                         throw new NestedException(e);
280                     }
281                     this.fBuffer.append(resolvedType);
282                 }
283             };
284             try {
285                 type.accept(flattener);
286             } catch (NestedException e) {
287                 throw ((CoreException) e.getCause());
288             }
289             return flattener.getResult();
290         }
291
292         private static String JavaDoc resolveType(String JavaDoc elementTypeName, RefactoringStatus status, IType declaringType, IProgressMonitor pm) throws CoreException {
293             String JavaDoc[][] fqns= declaringType.resolveType(elementTypeName);
294             if (fqns != null) {
295                 if (fqns.length == 1) {
296                     return JavaModelUtil.concatenateName(fqns[0][0], fqns[0][1]);
297                 } else if (fqns.length > 1){
298                     String JavaDoc[] keys= {elementTypeName, String.valueOf(fqns.length)};
299                     String JavaDoc msg= Messages.format(RefactoringCoreMessages.TypeContextChecker_ambiguous, keys);
300                     status.addError(msg);
301                     return elementTypeName;
302                 }
303             }
304             
305             List JavaDoc typeRefsFound= findTypeInfos(elementTypeName, declaringType, pm);
306             if (typeRefsFound.size() == 0){
307                 String JavaDoc[] keys= {elementTypeName};
308                 String JavaDoc msg= Messages.format(RefactoringCoreMessages.TypeContextChecker_not_unique, keys);
309                 status.addError(msg);
310                 return elementTypeName;
311             } else if (typeRefsFound.size() == 1){
312                 TypeNameMatch typeInfo= (TypeNameMatch) typeRefsFound.get(0);
313                 return typeInfo.getFullyQualifiedName();
314             } else {
315                 Assert.isTrue(typeRefsFound.size() > 1);
316                 String JavaDoc[] keys= {elementTypeName, String.valueOf(typeRefsFound.size())};
317                 String JavaDoc msg= Messages.format(RefactoringCoreMessages.TypeContextChecker_ambiguous, keys);
318                 status.addError(msg);
319                 return elementTypeName;
320             }
321         }
322
323         private static List JavaDoc findTypeInfos(String JavaDoc typeName, IType contextType, IProgressMonitor pm) throws JavaModelException {
324             IJavaSearchScope scope= SearchEngine.createJavaSearchScope(new IJavaProject[]{contextType.getJavaProject()}, true);
325             IPackageFragment currPackage= contextType.getPackageFragment();
326             ArrayList JavaDoc collectedInfos= new ArrayList JavaDoc();
327             TypeNameMatchCollector requestor= new TypeNameMatchCollector(collectedInfos);
328             int matchMode= SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE;
329             new SearchEngine().searchAllTypeNames(null, matchMode, typeName.toCharArray(), matchMode, IJavaSearchConstants.TYPE, scope, requestor, IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH, pm);
330             
331             List JavaDoc result= new ArrayList JavaDoc();
332             for (Iterator JavaDoc iter= collectedInfos.iterator(); iter.hasNext();) {
333                 TypeNameMatch curr= (TypeNameMatch) iter.next();
334                 IType type= curr.getType();
335                 if (type != null) {
336                     boolean visible=true;
337                     try {
338                         visible= JavaModelUtil.isVisible(type, currPackage);
339                     } catch (JavaModelException e) {
340                         //Assume visibile if not available
341
}
342                     if (visible) {
343                         result.add(curr);
344                     }
345                 }
346             }
347             return result;
348         }
349
350     }
351     
352     private static class MethodTypesSyntaxChecker {
353     
354         private final IMethod fMethod;
355         private final List JavaDoc/*<ParameterInfo>*/ fParameterInfos;
356         private final ReturnTypeInfo fReturnTypeInfo;
357     
358         public MethodTypesSyntaxChecker(IMethod method, List JavaDoc/*<ParameterInfo>*/ parameterInfos, ReturnTypeInfo returnTypeInfo) {
359             fMethod= method;
360             fParameterInfos= parameterInfos;
361             fReturnTypeInfo= returnTypeInfo;
362         }
363         
364         public RefactoringStatus[] checkSyntax() {
365             int parameterCount= fParameterInfos.size();
366             RefactoringStatus[] results= new RefactoringStatus[parameterCount + 1];
367             results[parameterCount]= checkReturnTypeSyntax();
368             for (int i= 0; i < parameterCount; i++) {
369                 ParameterInfo info= (ParameterInfo) fParameterInfos.get(i);
370                 results[i]= checkParameterTypeSyntax(info);
371             }
372             return results;
373         }
374         
375         private RefactoringStatus checkParameterTypeSyntax(ParameterInfo info) {
376             if (! info.isAdded() && ! info.isTypeNameChanged())
377                 return null;
378             return TypeContextChecker.checkParameterTypeSyntax(info.getNewTypeName(), fMethod.getJavaProject());
379         }
380         
381         private RefactoringStatus checkReturnTypeSyntax() {
382             String JavaDoc newTypeName= fReturnTypeInfo.getNewTypeName();
383             if ("".equals(newTypeName.trim())) { //$NON-NLS-1$
384
String JavaDoc msg= RefactoringCoreMessages.TypeContextChecker_return_type_not_empty;
385                 return RefactoringStatus.createFatalErrorStatus(msg);
386             }
387             List JavaDoc problemsCollector= new ArrayList JavaDoc(0);
388             Type parsedType= parseType(newTypeName, fMethod.getJavaProject(), problemsCollector);
389             if (parsedType == null) {
390                 String JavaDoc msg= Messages.format(RefactoringCoreMessages.TypeContextChecker_invalid_return_type, new String JavaDoc[]{newTypeName});
391                 return RefactoringStatus.createFatalErrorStatus(msg);
392             }
393             if (problemsCollector.size() == 0)
394                 return null;
395             
396             RefactoringStatus result= new RefactoringStatus();
397             for (Iterator JavaDoc iter= problemsCollector.iterator(); iter.hasNext();) {
398                 String JavaDoc msg= Messages.format(RefactoringCoreMessages.TypeContextChecker_invalid_return_type_syntax, new String JavaDoc[]{newTypeName, (String JavaDoc) iter.next()});
399                 result.addError(msg);
400             }
401             return result;
402         }
403
404         private static boolean isVoidArrayType(Type type){
405             if (! type.isArrayType())
406                 return false;
407             
408             ArrayType arrayType= (ArrayType)type;
409             if (! arrayType.getComponentType().isPrimitiveType())
410                 return false;
411             PrimitiveType primitiveType= (PrimitiveType)arrayType.getComponentType();
412             return (primitiveType.getPrimitiveTypeCode() == PrimitiveType.VOID);
413         }
414     
415     }
416
417     private static Type parseType(String JavaDoc typeString, IJavaProject javaProject, List JavaDoc/*<IProblem>*/ problemsCollector) {
418         if ("".equals(typeString.trim())) //speed up for a common case //$NON-NLS-1$
419
return null;
420         if (! typeString.trim().equals(typeString))
421             return null;
422     
423         StringBuffer JavaDoc cuBuff= new StringBuffer JavaDoc();
424         cuBuff.append("interface A{"); //$NON-NLS-1$
425
int offset= cuBuff.length();
426         cuBuff.append(typeString).append(" m();}"); //$NON-NLS-1$
427

428         ASTParser p= ASTParser.newParser(AST.JLS3);
429         p.setSource(cuBuff.toString().toCharArray());
430         p.setProject(javaProject);
431         CompilationUnit cu= (CompilationUnit) p.createAST(null);
432         Selection selection= Selection.createFromStartLength(offset, typeString.length());
433         SelectionAnalyzer analyzer= new SelectionAnalyzer(selection, false);
434         cu.accept(analyzer);
435         ASTNode selected= analyzer.getFirstSelectedNode();
436         if (!(selected instanceof Type))
437             return null;
438         Type type= (Type)selected;
439         if (MethodTypesSyntaxChecker.isVoidArrayType(type))
440             return null;
441         IProblem[] problems= ASTNodes.getProblems(type, ASTNodes.NODE_ONLY, ASTNodes.PROBLEMS);
442         if (problems.length > 0) {
443             for (int i= 0; i < problems.length; i++)
444                 problemsCollector.add(problems[i].getMessage());
445         }
446         
447         String JavaDoc typeNodeRange= cuBuff.substring(type.getStartPosition(), ASTNodes.getExclusiveEnd(type));
448         if (typeString.equals(typeNodeRange))
449             return type;
450         else
451             return null;
452     }
453
454     private static ITypeBinding handleBug84585(ITypeBinding typeBinding) {
455         if (typeBinding == null)
456             return null;
457         else if (typeBinding.isGenericType() && ! typeBinding.isRawType() && ! typeBinding.isParameterizedType())
458             return null; //see bug 84585
459
else
460             return typeBinding;
461     }
462
463     public static RefactoringStatus[] checkAndResolveMethodTypes(IMethod method, StubTypeContext stubTypeContext, List JavaDoc parameterInfos, ReturnTypeInfo returnTypeInfo, IProblemVerifier problemVerifier) throws CoreException {
464         MethodTypesChecker checker= new MethodTypesChecker(method, stubTypeContext, parameterInfos, returnTypeInfo, problemVerifier);
465         return checker.checkAndResolveMethodTypes();
466     }
467
468     public static RefactoringStatus[] checkMethodTypesSyntax(IMethod method, List JavaDoc parameterInfos, ReturnTypeInfo returnTypeInfo) {
469         MethodTypesSyntaxChecker checker= new MethodTypesSyntaxChecker(method, parameterInfos, returnTypeInfo);
470         return checker.checkSyntax();
471     }
472     
473     public static RefactoringStatus checkParameterTypeSyntax(String JavaDoc type, IJavaProject project) {
474         String JavaDoc newTypeName= ParameterInfo.stripEllipsis(type.trim()).trim();
475         
476         if ("".equals(newTypeName.trim())){ //$NON-NLS-1$
477
String JavaDoc msg= Messages.format(RefactoringCoreMessages.TypeContextChecker_parameter_type, new String JavaDoc[]{type});
478             return RefactoringStatus.createFatalErrorStatus(msg);
479         }
480         
481         if (ParameterInfo.isVarargs(type) && ! JavaModelUtil.is50OrHigher(project)) {
482             String JavaDoc msg= Messages.format(RefactoringCoreMessages.TypeContextChecker_no_vararg_below_50, new String JavaDoc[]{type});
483             return RefactoringStatus.createFatalErrorStatus(msg);
484         }
485         
486         List JavaDoc problemsCollector= new ArrayList JavaDoc(0);
487         Type parsedType= parseType(newTypeName, project, problemsCollector);
488         boolean valid= parsedType != null;
489         if (valid && parsedType instanceof PrimitiveType)
490             valid= ! PrimitiveType.VOID.equals(((PrimitiveType) parsedType).getPrimitiveTypeCode());
491         if (! valid) {
492             String JavaDoc msg= Messages.format(RefactoringCoreMessages.TypeContextChecker_invalid_type_name, new String JavaDoc[]{newTypeName});
493             return RefactoringStatus.createFatalErrorStatus(msg);
494         }
495         if (problemsCollector.size() == 0)
496             return null;
497         
498         RefactoringStatus result= new RefactoringStatus();
499         for (Iterator JavaDoc iter= problemsCollector.iterator(); iter.hasNext();) {
500             String JavaDoc msg= Messages.format(RefactoringCoreMessages.TypeContextChecker_invalid_type_syntax, new String JavaDoc[]{newTypeName, (String JavaDoc) iter.next()});
501             result.addError(msg);
502         }
503         return result;
504     }
505     
506     public static StubTypeContext createStubTypeContext(ICompilationUnit cu, CompilationUnit root, int focalPosition) throws CoreException {
507         IDocument document= RefactoringFileBuffers.acquire(cu).getDocument();
508         try {
509             StringBuffer JavaDoc bufBefore= new StringBuffer JavaDoc();
510             StringBuffer JavaDoc bufAfter= new StringBuffer JavaDoc();
511             
512             int introEnd= 0;
513             PackageDeclaration pack= root.getPackage();
514             if (pack != null)
515                 introEnd= pack.getStartPosition() + pack.getLength();
516             List JavaDoc imports= root.imports();
517             if (imports.size() > 0) {
518                 ImportDeclaration lastImport= (ImportDeclaration) imports.get(imports.size() - 1);
519                 introEnd= lastImport.getStartPosition() + lastImport.getLength();
520             }
521             try {
522                 bufBefore.append(document.get(0, introEnd));
523             } catch (BadLocationException e) {
524                 throw new RuntimeException JavaDoc(e); // doesn't happen
525
}
526             
527             fillWithTypeStubs(bufBefore, bufAfter, focalPosition, root.types());
528             bufBefore.append(' ');
529             bufAfter.insert(0, ' ');
530             return new StubTypeContext(cu, bufBefore.toString(), bufAfter.toString());
531             
532         } finally {
533             RefactoringFileBuffers.release(cu);
534         }
535     }
536
537     private static void fillWithTypeStubs(final StringBuffer JavaDoc bufBefore, final StringBuffer JavaDoc bufAfter, final int focalPosition, List JavaDoc/*<? extends BodyDeclaration>*/ types) {
538         StringBuffer JavaDoc buf;
539         for (Iterator JavaDoc iter= types.iterator(); iter.hasNext();) {
540             BodyDeclaration bodyDeclaration= (BodyDeclaration) iter.next();
541             if (! (bodyDeclaration instanceof AbstractTypeDeclaration)) {
542                 //account for local classes:
543
if (! (bodyDeclaration instanceof MethodDeclaration))
544                     continue;
545                 int bodyStart= bodyDeclaration.getStartPosition();
546                 int bodyEnd= bodyDeclaration.getStartPosition() + bodyDeclaration.getLength();
547                 if (! (bodyStart < focalPosition && focalPosition < bodyEnd))
548                     continue;
549                 MethodDeclaration methodDeclaration= (MethodDeclaration) bodyDeclaration;
550                 buf= bufBefore;
551                 appendModifiers(buf, methodDeclaration.modifiers());
552                 appendTypeParameters(buf, methodDeclaration.typeParameters());
553                 buf.append(" void "); //$NON-NLS-1$
554
buf.append(methodDeclaration.getName().getIdentifier());
555                 buf.append("(){\n"); //$NON-NLS-1$
556
Block body= methodDeclaration.getBody();
557                 body.accept(new HierarchicalASTVisitor() {
558                     public boolean visit(AbstractTypeDeclaration node) {
559                         fillWithTypeStubs(bufBefore, bufAfter, focalPosition, Collections.singletonList(node));
560                         return false;
561                     }
562                     public boolean visit(ClassInstanceCreation node) {
563                         AnonymousClassDeclaration anonDecl= node.getAnonymousClassDeclaration();
564                         if (anonDecl == null)
565                             return false;
566                         int anonStart= anonDecl.getStartPosition();
567                         int anonEnd= anonDecl.getStartPosition() + anonDecl.getLength();
568                         if (! (anonStart < focalPosition && focalPosition < anonEnd))
569                             return false;
570                         bufBefore.append(" new "); //$NON-NLS-1$
571
bufBefore.append(node.getType().toString());
572                         bufBefore.append("(){\n"); //$NON-NLS-1$
573
fillWithTypeStubs(bufBefore, bufAfter, focalPosition, anonDecl.bodyDeclarations());
574                         bufAfter.insert(0, "};\n"); //$NON-NLS-1$
575
return false;
576                     }
577                 });
578                 buf= bufAfter;
579                 buf.append("}\n"); //$NON-NLS-1$
580
continue;
581             }
582             
583             AbstractTypeDeclaration decl= (AbstractTypeDeclaration) bodyDeclaration;
584             buf= decl.getStartPosition() < focalPosition ? bufBefore : bufAfter;
585             appendModifiers(buf, decl.modifiers());
586             
587             if (decl instanceof TypeDeclaration) {
588                 TypeDeclaration type= (TypeDeclaration) decl;
589                 buf.append(type.isInterface() ? "interface " : "class "); //$NON-NLS-1$//$NON-NLS-2$
590
buf.append(type.getName().getIdentifier());
591                 appendTypeParameters(buf, type.typeParameters());
592                 if (type.getSuperclassType() != null) {
593                     buf.append(" extends "); //$NON-NLS-1$
594
buf.append(ASTNodes.asString(type.getSuperclassType()));
595                 }
596                 List JavaDoc superInterfaces= type.superInterfaceTypes();
597                 appendSuperInterfaces(buf, superInterfaces);
598                 
599             } else if (decl instanceof AnnotationTypeDeclaration) {
600                 AnnotationTypeDeclaration annotation= (AnnotationTypeDeclaration) decl;
601                 buf.append("@interface "); //$NON-NLS-1$
602
buf.append(annotation.getName().getIdentifier());
603                 
604             } else if (decl instanceof EnumDeclaration) {
605                 EnumDeclaration enumDecl= (EnumDeclaration) decl;
606                 buf.append("enum "); //$NON-NLS-1$
607
buf.append(enumDecl.getName().getIdentifier());
608                 List JavaDoc superInterfaces= enumDecl.superInterfaceTypes();
609                 appendSuperInterfaces(buf, superInterfaces);
610             }
611             
612             buf.append("{\n"); //$NON-NLS-1$
613
if (decl instanceof EnumDeclaration)
614                 buf.append(";\n"); //$NON-NLS-1$
615
fillWithTypeStubs(bufBefore, bufAfter, focalPosition, decl.bodyDeclarations());
616             buf= decl.getStartPosition() + decl.getLength() < focalPosition ? bufBefore : bufAfter;
617             buf.append("}\n"); //$NON-NLS-1$
618
}
619     }
620
621     private static void appendTypeParameters(StringBuffer JavaDoc buf, List JavaDoc typeParameters) {
622         int typeParametersCount= typeParameters.size();
623         if (typeParametersCount > 0) {
624             buf.append('<');
625             for (int i= 0; i < typeParametersCount; i++) {
626                 TypeParameter typeParameter= (TypeParameter) typeParameters.get(i);
627                 buf.append(ASTNodes.asString(typeParameter));
628                 if (i < typeParametersCount - 1)
629                     buf.append(',');
630             }
631         }
632     }
633
634     private static void appendModifiers(StringBuffer JavaDoc buf, List JavaDoc modifiers) {
635         for (Iterator JavaDoc iterator= modifiers.iterator(); iterator.hasNext();) {
636             IExtendedModifier extendedModifier= (IExtendedModifier) iterator.next();
637             if (extendedModifier.isModifier()) {
638                 Modifier modifier= (Modifier) extendedModifier;
639                 buf.append(modifier.getKeyword().toString()).append(' ');
640             }
641         }
642     }
643
644     private static void appendSuperInterfaces(StringBuffer JavaDoc buf, List JavaDoc superInterfaces) {
645         int superInterfaceCount= superInterfaces.size();
646         if (superInterfaceCount > 0) {
647             buf.append(" implements "); //$NON-NLS-1$
648
for (int i= 0; i < superInterfaceCount; i++) {
649                 Type superInterface= (Type) superInterfaces.get(i);
650                 buf.append(ASTNodes.asString(superInterface));
651                 if (i < superInterfaceCount - 1)
652                     buf.append(',');
653             }
654         }
655     }
656
657     public static StubTypeContext createSuperInterfaceStubTypeContext(String JavaDoc typeName, IType enclosingType, IPackageFragment packageFragment) {
658         return createSupertypeStubTypeContext(typeName, true, enclosingType, packageFragment);
659     }
660     
661     public static StubTypeContext createSuperClassStubTypeContext(String JavaDoc typeName, IType enclosingType, IPackageFragment packageFragment) {
662         return createSupertypeStubTypeContext(typeName, false, enclosingType, packageFragment);
663     }
664     
665     private static StubTypeContext createSupertypeStubTypeContext(String JavaDoc typeName, boolean isInterface, IType enclosingType, IPackageFragment packageFragment) {
666         StubTypeContext stubTypeContext;
667         String JavaDoc prolog= "class " + typeName + (isInterface ? " implements " : " extends "); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
668
String JavaDoc epilog= " {} "; //$NON-NLS-1$
669
if (enclosingType != null) {
670             try {
671                 ICompilationUnit cu= enclosingType.getCompilationUnit();
672                 ISourceRange typeSourceRange= enclosingType.getSourceRange();
673                 int focalPosition= typeSourceRange.getOffset() + typeSourceRange.getLength() - 1; // before closing brace
674

675                 ASTParser parser= ASTParser.newParser(AST.JLS3);
676                 parser.setSource(cu);
677                 parser.setFocalPosition(focalPosition);
678                 CompilationUnit compilationUnit= (CompilationUnit) parser.createAST(null);
679     
680                 stubTypeContext= createStubTypeContext(cu, compilationUnit, focalPosition);
681                 stubTypeContext= new StubTypeContext(stubTypeContext.getCuHandle(),
682                         stubTypeContext.getBeforeString() + prolog,
683                         epilog + stubTypeContext.getAfterString());
684             } catch (CoreException e) {
685                 JavaPlugin.log(e);
686                 stubTypeContext= new StubTypeContext(null, null, null);
687             }
688             
689         } else if (packageFragment != null) {
690             ICompilationUnit cu= packageFragment.getCompilationUnit(JavaTypeCompletionProcessor.DUMMY_CU_NAME);
691             stubTypeContext= new StubTypeContext(cu, "package " + packageFragment.getElementName() + ";" + prolog, epilog); //$NON-NLS-1$//$NON-NLS-2$
692

693         } else {
694             stubTypeContext= new StubTypeContext(null, null, null);
695         }
696         return stubTypeContext;
697     }
698
699     public static Type parseSuperClass(String JavaDoc superClass) {
700         return parseSuperType(superClass, false);
701     }
702
703     public static Type parseSuperInterface(String JavaDoc superInterface) {
704         return parseSuperType(superInterface, true);
705     }
706
707     private static Type parseSuperType(String JavaDoc superType, boolean isInterface) {
708         if (! superType.trim().equals(superType)) {
709             return null;
710         }
711     
712         StringBuffer JavaDoc cuBuff= new StringBuffer JavaDoc();
713         if (isInterface)
714             cuBuff.append("class __X__ implements "); //$NON-NLS-1$
715
else
716             cuBuff.append("class __X__ extends "); //$NON-NLS-1$
717
int offset= cuBuff.length();
718         cuBuff.append(superType).append(" {}"); //$NON-NLS-1$
719

720         ASTParser p= ASTParser.newParser(AST.JLS3);
721         p.setSource(cuBuff.toString().toCharArray());
722         Map JavaDoc options= new HashMap JavaDoc();
723         JavaModelUtil.set50CompilanceOptions(options);
724         p.setCompilerOptions(options);
725         CompilationUnit cu= (CompilationUnit) p.createAST(null);
726         ASTNode selected= NodeFinder.perform(cu, offset, superType.length());
727         if (selected instanceof Name)
728             selected= selected.getParent();
729         if (selected.getStartPosition() != offset
730                 || selected.getLength() != superType.length()
731                 || ! (selected instanceof Type)
732                 || selected instanceof PrimitiveType) {
733             return null;
734         }
735         Type type= (Type) selected;
736         
737         String JavaDoc typeNodeRange= cuBuff.substring(type.getStartPosition(), ASTNodes.getExclusiveEnd(type));
738         if (! superType.equals(typeNodeRange)){
739             return null;
740         }
741         return type;
742     }
743
744     public static ITypeBinding resolveSuperClass(String JavaDoc superclass, IType typeHandle, StubTypeContext superClassContext) {
745         StringBuffer JavaDoc cuString= new StringBuffer JavaDoc();
746         cuString.append(superClassContext.getBeforeString());
747         cuString.append(superclass);
748         cuString.append(superClassContext.getAfterString());
749         
750         try {
751             ICompilationUnit wc= typeHandle.getCompilationUnit().getWorkingCopy(new WorkingCopyOwner() {/*subclass*/}, new NullProgressMonitor());
752             try {
753                 wc.getBuffer().setContents(cuString.toString());
754                 CompilationUnit compilationUnit= new RefactoringASTParser(AST.JLS3).parse(wc, true);
755                 ASTNode type= NodeFinder.perform(compilationUnit, superClassContext.getBeforeString().length(),
756                         superclass.length());
757                 if (type instanceof Type) {
758                     return handleBug84585(((Type) type).resolveBinding());
759                 } else if (type instanceof Name) {
760                     ASTNode parent= type.getParent();
761                     if (parent instanceof Type)
762                         return handleBug84585(((Type) parent).resolveBinding());
763                 }
764                 throw new IllegalStateException JavaDoc();
765             } finally {
766                 wc.discardWorkingCopy();
767             }
768         } catch (JavaModelException e) {
769             return null;
770         }
771     }
772
773     public static ITypeBinding[] resolveSuperInterfaces(String JavaDoc[] interfaces, IType typeHandle, StubTypeContext superInterfaceContext) {
774         ITypeBinding[] result= new ITypeBinding[interfaces.length];
775         
776         int[] interfaceOffsets= new int[interfaces.length];
777         StringBuffer JavaDoc cuString= new StringBuffer JavaDoc();
778         cuString.append(superInterfaceContext.getBeforeString());
779         int last= interfaces.length - 1;
780         for (int i= 0; i <= last; i++) {
781             interfaceOffsets[i]= cuString.length();
782             cuString.append(interfaces[i]);
783             if (i != last)
784                 cuString.append(", "); //$NON-NLS-1$
785
}
786         cuString.append(superInterfaceContext.getAfterString());
787         
788         try {
789             ICompilationUnit wc= typeHandle.getCompilationUnit().getWorkingCopy(new WorkingCopyOwner() {/*subclass*/}, new NullProgressMonitor());
790             try {
791                 wc.getBuffer().setContents(cuString.toString());
792                 CompilationUnit compilationUnit= new RefactoringASTParser(AST.JLS3).parse(wc, true);
793                 for (int i= 0; i <= last; i++) {
794                     ASTNode type= NodeFinder.perform(compilationUnit, interfaceOffsets[i], interfaces[i].length());
795                     if (type instanceof Type) {
796                         result[i]= handleBug84585(((Type) type).resolveBinding());
797                     } else if (type instanceof Name) {
798                         ASTNode parent= type.getParent();
799                         if (parent instanceof Type) {
800                             result[i]= handleBug84585(((Type) parent).resolveBinding());
801                         } else {
802                             throw new IllegalStateException JavaDoc();
803                         }
804                     } else {
805                         throw new IllegalStateException JavaDoc();
806                     }
807                 }
808             } finally {
809                 wc.discardWorkingCopy();
810             }
811         } catch (JavaModelException e) {
812             // won't happen
813
}
814         return result;
815     }
816 }
817
Popular Tags