2
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
6
* The contents of this file are subject to the terms of either the GNU
7
* General Public License Version 2 only ("GPL") or the Common
8
* Development and Distribution License("CDDL") (collectively, the
9
* "License"). You may not use this file except in compliance with the
10
* License. You can obtain a copy of the License at
11
* http://www.netbeans.org/cddl-gplv2.html
12
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
* specific language governing permissions and limitations under the
14
* License. When distributing the software, include this License Header
15
* Notice in each file and include the License file at
16
* nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
17
* particular file as subject to the "Classpath" exception as provided
18
* by Sun in the GPL Version 2 section of the License file that
19
* accompanied this code. If applicable, add the following below the
20
* License Header, with the fields enclosed by brackets [] replaced by
21
* your own identifying information:
22
* "Portions Copyrighted [year] [name of copyright owner]"
26
* Portions Copyrighted 2007 Sun Microsystems, Inc.
28
package org.netbeans.modules.java.hints.errors;
30
import com.sun.source.tree.BlockTree;
31
import com.sun.source.tree.ClassTree;
32
import com.sun.source.tree.ExpressionTree;
33
import com.sun.source.tree.MethodTree;
34
import com.sun.source.tree.NewClassTree;
35
import com.sun.source.tree.StatementTree;
36
import com.sun.source.tree.TypeParameterTree;
37
import com.sun.source.tree.VariableTree;
38
import com.sun.source.util.TreePath;
39
import java.io.IOException;
40
import java.util.ArrayList;
41
import java.util.Collections;
42
import java.util.EnumSet;
43
import java.util.Iterator;
44
import java.util.List;
46
import java.util.logging.Level;
47
import javax.lang.model.element.ElementKind;
48
import javax.lang.model.element.Modifier;
49
import javax.lang.model.element.TypeElement;
50
import javax.lang.model.type.TypeKind;
51
import javax.lang.model.type.TypeMirror;
52
import org.netbeans.api.java.source.Task;
53
import org.netbeans.api.java.source.ClasspathInfo;
54
import org.netbeans.api.java.source.CompilationInfo;
55
import org.netbeans.api.java.source.ElementHandle;
56
import org.netbeans.api.java.source.JavaSource;
57
import org.netbeans.api.java.source.JavaSource.Phase;
58
import org.netbeans.api.java.source.ModificationResult;
59
import org.netbeans.api.java.source.SourceUtils;
60
import org.netbeans.api.java.source.TreeMaker;
61
import org.netbeans.api.java.source.TypeMirrorHandle;
62
import org.netbeans.api.java.source.WorkingCopy;
63
import org.netbeans.modules.java.editor.codegen.GeneratorUtils;
64
import org.netbeans.modules.java.hints.infrastructure.ErrorHintsProvider;
65
import org.netbeans.spi.editor.hints.ChangeInfo;
66
import org.netbeans.spi.editor.hints.Fix;
67
import org.openide.filesystems.FileObject;
68
import org.openide.util.NbBundle;
74
public final class CreateMethodFix implements Fix {
76
private FileObject targetFile;
77
private ElementHandle<TypeElement> target;
78
private TypeMirrorHandle returnType;
79
private List<TypeMirrorHandle> argumentTypes;
80
private List<String> argumentNames;
81
private ClasspathInfo cpInfo;
82
private Set<Modifier> modifiers;
86
private String methodDisplayName;
88
public CreateMethodFix(CompilationInfo info, String name, Set<Modifier> modifiers, TypeElement target, TypeMirror returnType, List<? extends TypeMirror> argumentTypes, List<String> argumentNames) {
90
this.inFQN = target.getQualifiedName().toString();
91
this.cpInfo = info.getClasspathInfo();
92
this.modifiers = modifiers;
93
this.targetFile = SourceUtils.getFile(target, cpInfo);
94
this.target = ElementHandle.create(target);
95
if (returnType != null && returnType.getKind() == TypeKind.NULL) {
96
returnType = info.getElements().getTypeElement("java.lang.Object").asType(); // NOI18N
98
this.returnType = returnType != null ? TypeMirrorHandle.create(returnType) : null;
99
this.argumentTypes = new ArrayList<TypeMirrorHandle>();
101
for (TypeMirror tm : argumentTypes) {
102
this.argumentTypes.add(TypeMirrorHandle.create(tm));
105
this.argumentNames = argumentNames;
107
StringBuilder methodDisplayName = new StringBuilder();
109
if (returnType != null) {
110
methodDisplayName.append(name);
112
methodDisplayName.append(target.getSimpleName().toString());
115
methodDisplayName.append('(');
117
boolean first = true;
119
for (TypeMirror tm : argumentTypes) {
121
methodDisplayName.append(','); // NOI18N
123
methodDisplayName.append(org.netbeans.modules.editor.java.Utilities.getTypeName(tm, true));
126
methodDisplayName.append(')'); // NOI18N
128
this.methodDisplayName = methodDisplayName.toString();
131
public String getText() {
132
if(target.getKind() == ElementKind.ANNOTATION_TYPE)
133
return NbBundle.getMessage(CreateMethodFix.class, "LBL_FIX_Create_Annotation_Element", methodDisplayName, inFQN );
134
if (returnType != null) {
135
return NbBundle.getMessage(CreateMethodFix.class, "LBL_FIX_Create_Method", methodDisplayName, inFQN );
137
return NbBundle.getMessage(CreateMethodFix.class, "LBL_FIX_Create_Constructor", methodDisplayName, inFQN );
141
public ChangeInfo implement() throws IOException {
142
//use the original cp-info so it is "sure" that the proposedType can be resolved:
143
JavaSource js = JavaSource.create(cpInfo, targetFile);
145
ModificationResult diff = js.runModificationTask(new Task<WorkingCopy>() {
146
public void run(final WorkingCopy working) throws IOException {
147
working.toPhase(Phase.RESOLVED);
148
TypeElement targetType = target.resolve(working);
150
if (targetType == null) {
151
ErrorHintsProvider.LOG.log(Level.INFO, "Cannot resolve target."); // NOI18N
155
TreePath targetTree = working.getTrees().getPath(targetType);
157
if (targetTree == null) {
158
ErrorHintsProvider.LOG.log(Level.INFO, "Cannot resolve target tree: " + targetType.getQualifiedName() + "."); // NOI18N
162
TypeMirrorHandle returnTypeHandle = CreateMethodFix.this.returnType;
163
TypeMirror returnType = returnTypeHandle != null ? returnTypeHandle.resolve(working) : null;
165
if (returnTypeHandle != null && returnType == null) {
166
ErrorHintsProvider.LOG.log(Level.INFO, "Cannot resolve proposed type."); // NOI18N
170
TreeMaker make = working.getTreeMaker();
172
List<VariableTree> argTypes = new ArrayList<VariableTree>();
173
Iterator<TypeMirrorHandle> typeIt = CreateMethodFix.this.argumentTypes.iterator();
174
Iterator<String> nameIt = CreateMethodFix.this.argumentNames.iterator();
176
while (typeIt.hasNext() && nameIt.hasNext()) {
177
TypeMirrorHandle tmh = typeIt.next();
178
String argName = nameIt.next();
180
argTypes.add(make.Variable(make.Modifiers(EnumSet.noneOf(Modifier.class)), argName, make.Type(tmh.resolve(working)), null));
183
BlockTree body = targetType.getKind().isClass() ? createDefaultMethodBody(working, returnType) : null;
184
MethodTree mt = make.Method(make.Modifiers(modifiers), name, returnType != null ? make.Type(returnType) : null, Collections.<TypeParameterTree>emptyList(), argTypes, Collections.<ExpressionTree>emptyList(), body, null);
185
ClassTree decl = GeneratorUtils.insertClassMember(working, targetTree, mt);
187
working.rewrite(targetTree.getLeaf(), decl);
191
return Utilities.commitAndComputeChangeInfo(targetFile, diff);
194
private void addArguments(CompilationInfo info, StringBuilder value) {
195
value.append("("); // NOI18N
197
Iterator<TypeMirrorHandle> typeIt = CreateMethodFix.this.argumentTypes.iterator();
198
Iterator<String> nameIt = CreateMethodFix.this.argumentNames.iterator();
199
boolean first = true;
201
while (typeIt.hasNext() && nameIt.hasNext()) {
207
TypeMirrorHandle tmh = typeIt.next();
208
String argName = nameIt.next();
210
value.append(org.netbeans.modules.editor.java.Utilities.getTypeName(tmh.resolve(info), true));
211
value.append(' '); // NOI18N
212
value.append(argName);
215
value.append(")"); // NOI18N
218
public String toDebugString(CompilationInfo info) {
219
StringBuilder value = new StringBuilder();
221
if (returnType != null) {
222
value.append("CreateMethodFix:"); // NOI18N
224
addArguments(info, value);
225
value.append(org.netbeans.modules.editor.java.Utilities.getTypeName(returnType.resolve(info), true));
227
value.append("CreateConstructorFix:"); // NOI18N
228
addArguments(info, value);
231
value.append(':'); // NOI18N
232
value.append(inFQN); // NOI18N
234
return value.toString();
237
//XXX should be moved into the GeneratorUtils:
238
private static BlockTree createDefaultMethodBody(WorkingCopy wc, TypeMirror returnType) {
239
TreeMaker make = wc.getTreeMaker();
240
List<StatementTree> blockStatements = new ArrayList<StatementTree>();
241
TypeElement uoe = wc.getElements().getTypeElement("java.lang.UnsupportedOperationException"); // NOI18N
243
NewClassTree nue = make.NewClass(null, Collections.<ExpressionTree>emptyList(), make.QualIdent(uoe), Collections.singletonList(make.Literal("Not yet implemented")), null);
244
blockStatements.add(make.Throw(nue));
246
return make.Block(blockStatements, false);