This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

View | Details | Raw Unified | Return to bug 89258
Collapse All | Expand All

(-)a/java.editor/src/org/netbeans/modules/java/editor/imports/JavaFixAllImports.java (-30 / +11 lines)
Lines 51-57 Link Here
51
import java.awt.Toolkit;
51
import java.awt.Toolkit;
52
import java.io.IOException;
52
import java.io.IOException;
53
import java.util.ArrayList;
53
import java.util.ArrayList;
54
import java.util.Collections;
55
import java.util.HashMap;
54
import java.util.HashMap;
56
import java.util.List;
55
import java.util.List;
57
import java.util.Map;
56
import java.util.Map;
Lines 62-67 Link Here
62
import org.netbeans.api.java.source.Task;
61
import org.netbeans.api.java.source.Task;
63
import org.netbeans.api.java.source.JavaSource;
62
import org.netbeans.api.java.source.JavaSource;
64
import org.netbeans.api.java.source.JavaSource.Phase;
63
import org.netbeans.api.java.source.JavaSource.Phase;
64
import org.netbeans.api.java.source.SourceUtils;
65
import org.netbeans.api.java.source.TreeMaker;
65
import org.netbeans.api.java.source.TreeMaker;
66
import org.netbeans.api.java.source.TreePathHandle;
66
import org.netbeans.api.java.source.TreePathHandle;
67
import org.netbeans.api.java.source.WorkingCopy;
67
import org.netbeans.api.java.source.WorkingCopy;
Lines 332-368 Link Here
332
        }
332
        }
333
    }
333
    }
334
334
335
    //XXX: copied from SourceUtils.addImports. Ideally, should be on one place only:
335
    /**
336
     * @param cut
337
     * @param toImport
338
     * @param make
339
     * @return
340
     * @deprecated use {@link SourceUtils#addImports(CompilationUnitTree, List, TreeMaker)}
341
     * @throws IOException a big fat lie! Kept for legacy.
342
     */
343
    @Deprecated
336
    public static CompilationUnitTree addImports(CompilationUnitTree cut, List<String> toImport, TreeMaker make)
344
    public static CompilationUnitTree addImports(CompilationUnitTree cut, List<String> toImport, TreeMaker make)
337
        throws IOException {
345
        throws IOException {
338
        // do not modify the list given by the caller (may be reused or immutable).
346
        return SourceUtils.addImports(cut, toImport, make);
339
        toImport = new ArrayList<String>(toImport); 
340
        Collections.sort(toImport);
341
342
        List<ImportTree> imports = new ArrayList<ImportTree>(cut.getImports());
343
        int currentToImport = toImport.size() - 1;
344
        int currentExisting = imports.size() - 1;
345
        
346
        while (currentToImport >= 0 && currentExisting >= 0) {
347
            String currentToImportText = toImport.get(currentToImport);
348
            
349
            while (currentExisting >= 0 && (imports.get(currentExisting).isStatic() || imports.get(currentExisting).getQualifiedIdentifier().toString().compareTo(currentToImportText) > 0))
350
                currentExisting--;
351
            
352
            if (currentExisting >= 0) {
353
                imports.add(currentExisting+1, make.Import(make.Identifier(currentToImportText), false));
354
                currentToImport--;
355
            }
356
        }
357
        // we are at the head of import section and we still have some imports
358
        // to add, put them to the very beginning
359
        while (currentToImport >= 0) {
360
            String importText = toImport.get(currentToImport);
361
            imports.add(0, make.Import(make.Identifier(importText), false));
362
            currentToImport--;
363
        }
364
        // return a copy of the unit with changed imports section
365
        return make.CompilationUnit(cut.getPackageName(), imports, cut.getTypeDecls(), cut.getSourceFile());
366
    }
347
    }
367
    
348
    
368
}
349
}
(-)a/java.hints/src/org/netbeans/modules/java/hints/Bundle.properties (-1 / +7 lines)
Lines 76-82 Link Here
76
LBL_Imports_EXCLUDED=Import from Excluded
76
LBL_Imports_EXCLUDED=Import from Excluded
77
LBL_Imports_STAR=Star import
77
LBL_Imports_STAR=Star import
78
78
79
DSC_Imports_DELAGATE=Delegate - non GUI
79
DSC_Imports_DELEGATE=Delegate - non GUI
80
DSC_Imports_UNUSED=Unused Import
80
DSC_Imports_UNUSED=Unused Import
81
DSC_Imports_DUPLICATE=Multiple Import
81
DSC_Imports_DUPLICATE=Multiple Import
82
DSC_Imports_SAME_PACKAGE=Import From The Same Package
82
DSC_Imports_SAME_PACKAGE=Import From The Same Package
Lines 262-267 Link Here
262
ERR_SynchronizationOnNonFinalField=Synchronization on non-final field
262
ERR_SynchronizationOnNonFinalField=Synchronization on non-final field
263
DN_SynchronizationOnNonFinalField=Synchronization on non-final field
263
DN_SynchronizationOnNonFinalField=Synchronization on non-final field
264
264
265
HINT_StaticImport=Convert method to static import
266
HINT_StaticImport2=Static import for {0}
267
DSC_StaticImport=Convert method to static import
268
ERR_StaticImport=Convert method to static import
269
DN_StaticImport=Convert method to static import
270
265
HINT_SuspiciousCall=Suspicious call to {0}:\nExpected type {2}, actual type {1}
271
HINT_SuspiciousCall=Suspicious call to {0}:\nExpected type {2}, actual type {1}
266
HINT_SuspiciousCallIncompatibleTypes=Suspicious call to {0}:\nGiven object cannot contain instances of {1} (expected {2})
272
HINT_SuspiciousCallIncompatibleTypes=Suspicious call to {0}:\nGiven object cannot contain instances of {1} (expected {2})
267
DN_CollectionRemove=Suspicous method call
273
DN_CollectionRemove=Suspicous method call
(-)56ddb85f80ca (+346 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
5
 *
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]"
23
 *
24
 * Contributor(s):
25
 *
26
 * Portions Copyrighted 2009 Sun Microsystems, Inc.
27
 */
28
package org.netbeans.modules.java.hints;
29
30
import com.sun.source.tree.CompilationUnitTree;
31
import com.sun.source.tree.ExpressionTree;
32
import com.sun.source.tree.ImportTree;
33
import com.sun.source.tree.MethodInvocationTree;
34
import com.sun.source.tree.Tree.Kind;
35
import com.sun.source.util.TreePath;
36
import java.util.Collections;
37
import java.util.EnumSet;
38
import java.util.List;
39
import java.util.Set;
40
import java.util.concurrent.atomic.AtomicBoolean;
41
import javax.lang.model.element.Element;
42
import javax.lang.model.element.ElementKind;
43
import javax.lang.model.element.Modifier;
44
import javax.lang.model.element.TypeElement;
45
import javax.lang.model.type.TypeMirror;
46
import javax.lang.model.util.Types;
47
import org.netbeans.api.java.source.CompilationInfo;
48
import org.netbeans.api.java.source.ElementUtilities;
49
import org.netbeans.api.java.source.JavaSource;
50
import org.netbeans.api.java.source.JavaSource.Phase;
51
import org.netbeans.api.java.source.SourceUtils;
52
import org.netbeans.api.java.source.Task;
53
import org.netbeans.api.java.source.TreeMaker;
54
import org.netbeans.api.java.source.TreePathHandle;
55
import org.netbeans.api.java.source.WorkingCopy;
56
import org.netbeans.modules.java.hints.spi.AbstractHint;
57
import org.netbeans.spi.editor.hints.ChangeInfo;
58
import org.netbeans.spi.editor.hints.ErrorDescription;
59
import org.netbeans.spi.editor.hints.ErrorDescriptionFactory;
60
import org.netbeans.spi.editor.hints.Fix;
61
import org.openide.util.NbBundle;
62
import static org.netbeans.modules.editor.java.Utilities.getElementName;
63
64
/**
65
 * Hint offering to convert a qualified static method into a static import. e.g.
66
 * <code>Math.abs(-1)</code> -> <code>abs(-1)</code>.
67
 *
68
 * @author Sam Halliday
69
 * @see <a href="http://www.netbeans.org/issues/show_bug.cgi?id=89258">RFE 89258</a>
70
 */
71
public class StaticImport extends AbstractHint {
72
73
    private final AtomicBoolean cancel = new AtomicBoolean();
74
75
    public StaticImport() {
76
        super(true, false, HintSeverity.CURRENT_LINE_WARNING);
77
    }
78
79
    @Override
80
    public String getDescription() {
81
        return NbBundle.getMessage(StaticImport.class, "DSC_StaticImport");
82
    }
83
84
    public Set<Kind> getTreeKinds() {
85
        return EnumSet.of(Kind.METHOD_INVOCATION);
86
    }
87
88
    public List<ErrorDescription> run(CompilationInfo info, TreePath treePath) {
89
        if (treePath.getLeaf().getKind() != Kind.METHOD_INVOCATION) {
90
            return null;
91
        }
92
        cancel.set(false);
93
        MethodInvocationTree tree = (MethodInvocationTree) treePath.getLeaf();
94
        ExpressionTree identifier = tree.getMethodSelect();
95
        if (identifier.getKind() != Kind.MEMBER_SELECT) {
96
            return null;
97
        }
98
        Element e = info.getTrees().getElement(new TreePath(treePath, identifier));
99
        if (e == null || !e.getModifiers().contains(Modifier.STATIC)) {
100
            return null;
101
        }
102
        Element enclosingEl = e.getEnclosingElement();
103
        if (enclosingEl == null) {
104
            return null;
105
        }
106
        // XXX is there a better way to ignore error cases
107
        String sn = e.getSimpleName().toString();
108
        if (!isValidStaticMethod(info, getElementName(enclosingEl, true).toString(), sn)) {
109
            return null;
110
        }
111
        // TODO ignore case where source code is less than Java 1.5
112
        Element klass = info.getTrees().getElement(getContainingClass(treePath));
113
        String fqn = null;
114
        String fqn1 = getMethodFqn(e);
115
        if (!isSubTypeOrInnerOfSubType(info, klass, enclosingEl) && !isStaticallyImported(info, fqn1)) {
116
            if (hasMethodNameClash(info, klass, sn) || hasStaticImportSimpleNameClash(info, sn)) {
117
                return null;
118
            }
119
            fqn = fqn1;
120
        }
121
        List<Fix> fixes = Collections.<Fix>singletonList(new FixImpl(TreePathHandle.create(treePath, info), fqn));
122
        String desc = NbBundle.getMessage(AddOverrideAnnotation.class, "HINT_StaticImport");
123
        int start = (int) info.getTrees().getSourcePositions().getStartPosition(info.getCompilationUnit(), identifier);
124
        int end = (int) info.getTrees().getSourcePositions().getEndPosition(info.getCompilationUnit(), identifier);
125
        ErrorDescription ed = ErrorDescriptionFactory.createErrorDescription(getSeverity().toEditorSeverity(), desc, fixes, info.getFileObject(), start, end);
126
        if (cancel.get()) {
127
            return null;
128
        }
129
        return Collections.singletonList(ed);
130
    }
131
132
    public String getId() {
133
        return StaticImport.class.getName();
134
    }
135
136
    public String getDisplayName() {
137
        return NbBundle.getMessage(StaticImport.class, "DSC_StaticImport");
138
    }
139
140
    public void cancel() {
141
        cancel.set(true);
142
    }
143
144
    public static final class FixImpl implements Fix, Task<WorkingCopy> {
145
146
        private final TreePathHandle handle;
147
        private final String fqn;
148
149
        /**
150
         * @param handle to the METHOD_INVOCATION
151
         * @param fqn to statically import, or null to not perform any imports
152
         */
153
        public FixImpl(TreePathHandle handle, String fqn) {
154
            this.handle = handle;
155
            this.fqn = fqn;
156
        }
157
158
        public String getText() {
159
            if (fqn == null) {
160
                return NbBundle.getMessage(StaticImport.class, "HINT_StaticImport");
161
            } else {
162
                return NbBundle.getMessage(StaticImport.class, "HINT_StaticImport2", fqn);
163
            }
164
        }
165
166
        public ChangeInfo implement() throws Exception {
167
            JavaSource js = JavaSource.forFileObject(handle.getFileObject());
168
            js.runModificationTask(this).commit();
169
            return null;
170
        }
171
172
        public void run(WorkingCopy copy) throws Exception {
173
            if (copy.toPhase(Phase.RESOLVED).compareTo(Phase.RESOLVED) < 0) {
174
                return;
175
            }
176
            TreePath treePath = handle.resolve(copy);
177
            if (treePath == null || treePath.getLeaf().getKind() != Kind.METHOD_INVOCATION) {
178
                return;
179
            }
180
            MethodInvocationTree tree = (MethodInvocationTree) treePath.getLeaf();
181
            ExpressionTree identifier = tree.getMethodSelect();
182
            Element e = copy.getTrees().getElement(new TreePath(treePath, identifier));
183
            if (e == null || !e.getModifiers().contains(Modifier.STATIC) || identifier.getKind() != Kind.MEMBER_SELECT) {
184
                return;
185
            }
186
            TreeMaker make = copy.getTreeMaker();
187
            copy.rewrite(identifier, make.Identifier(e.getSimpleName()));
188
            if (fqn == null) {
189
                return;
190
            }
191
            CompilationUnitTree cut = copy.getCompilationUnit();
192
            CompilationUnitTree nue = SourceUtils.addStaticImports(cut, Collections.singletonList(fqn), make);
193
            copy.rewrite(cut, nue);
194
        }
195
    }
196
197
    // returns true if a METHOD is enclosed in element with simple name sn
198
    private static boolean hasMethodWithSimpleName(CompilationInfo info, Element element, final String sn) {
199
        Iterable<? extends Element> members =
200
                info.getElementUtilities().getMembers(element.asType(), new ElementUtilities.ElementAcceptor() {
201
202
            public boolean accept(Element e, TypeMirror type) {
203
                if (e.getKind() == ElementKind.METHOD && e.getSimpleName().toString().equals(sn)) {
204
                    return true;
205
                }
206
                return false;
207
            }
208
        });
209
        return members.iterator().hasNext();
210
    }
211
212
    /**
213
     * @param info
214
     * @param simpleName of static method.
215
     * @return true if a static import exists with the same simple name.
216
     * Caveat, expect false positives on protected and default visibility methods from wildcard static imports.
217
     */
218
    public static boolean hasStaticImportSimpleNameClash(CompilationInfo info, String simpleName) {
219
        for (ImportTree i : info.getCompilationUnit().getImports()) {
220
            if (!i.isStatic()) {
221
                continue;
222
            }
223
            String q = i.getQualifiedIdentifier().toString();
224
            if (q.endsWith(".*")) { //NOI18N
225
                TypeElement ie = info.getElements().getTypeElement(q.substring(0, q.length() - 2));
226
                if (ie == null) {
227
                    continue;
228
                }
229
                for (Element enclosed : ie.getEnclosedElements()) {
230
                    Set<Modifier> modifiers = enclosed.getModifiers();
231
                    if (enclosed.getKind() != ElementKind.METHOD || !modifiers.contains(Modifier.STATIC) || modifiers.contains(Modifier.PRIVATE)) {
232
                        continue;
233
                    }
234
                    String sn1 = enclosed.getSimpleName().toString();
235
                    if (simpleName.equals(sn1)) {
236
                        return true;
237
                    }
238
                }
239
            } else {
240
                int endIndex = q.lastIndexOf("."); //NOI18N
241
                if (endIndex == -1 || endIndex >= q.length() - 1) {
242
                    continue;
243
                }
244
                if (q.substring(endIndex).equals(simpleName)) {
245
                    return true;
246
                }
247
            }
248
        }
249
        return false;
250
    }
251
252
    /**
253
     * @param info
254
     * @param t1
255
     * @param t3
256
     * @return true iff the first type (or its containing class in the case of inner classes)
257
     * is a subtype of the second.
258
     * @see Types#isSubtype(javax.lang.model.type.TypeMirror, javax.lang.model.type.TypeMirror)
259
     */
260
    private static boolean isSubTypeOrInnerOfSubType(CompilationInfo info, Element t1, Element t2) {
261
        boolean isSubtype = info.getTypes().isSubtype(t1.asType(), t2.asType());
262
        boolean isInnerClass = t1.getEnclosingElement().getKind() == ElementKind.CLASS;
263
        return isSubtype || (isInnerClass && info.getTypes().isSubtype(t1.getEnclosingElement().asType(), t2.asType()));
264
    }
265
266
    /**
267
     * @param info
268
     * @param klass the element for a CLASS
269
     * @param member the STATIC, MEMBER_SELECT Element for a MethodInvocationTree
270
     * @return true if member has a simple name which would clash with local or inherited
271
     * methods in klass (which may be an inner or static class).
272
     */
273
    public static boolean hasMethodNameClash(CompilationInfo info, Element klass, String simpleName) {
274
        assert klass != null;
275
        assert klass.getKind() == ElementKind.CLASS;
276
277
        // check the members and inherited members of the klass
278
        if (hasMethodWithSimpleName(info, klass, simpleName)) {
279
            return true;
280
        }
281
        Element klassEnclosing = klass.getEnclosingElement();
282
        return (klassEnclosing != null && klassEnclosing.getKind() == ElementKind.CLASS && hasMethodWithSimpleName(info, klassEnclosing, simpleName));
283
    }
284
285
    /**
286
     * @param e
287
     * @return the FQN for a METHOD Element
288
     */
289
    public static String getMethodFqn(Element e) {
290
        // TODO: or alternatively, upgrade getElementName to handled METHOD
291
        assert e.getKind() == ElementKind.METHOD;
292
        return getElementName(e.getEnclosingElement(), true) + "." + e.getSimpleName();
293
    }
294
295
    /**
296
     * @param tp
297
     * @return the first path which is a CLASS or null if none found
298
     */
299
    public static TreePath getContainingClass(TreePath tp) {
300
        while (tp != null && tp.getLeaf().getKind() != Kind.CLASS) {
301
            tp = tp.getParentPath();
302
        }
303
        return tp;
304
    }
305
306
    // return true if the fqn already has a static import
307
    private static boolean isStaticallyImported(CompilationInfo info, String fqn) {
308
        for (ImportTree i : info.getCompilationUnit().getImports()) {
309
            if (!i.isStatic()) {
310
                continue;
311
            }
312
            String q = i.getQualifiedIdentifier().toString();
313
            if (q.endsWith(".*") && fqn.startsWith(q.substring(0, q.length() - 1))) { //NOI18N
314
                return true;
315
            }
316
            if (q.equals(fqn)) {
317
                return true;
318
            }
319
        }
320
        return false;
321
    }
322
323
    /**
324
     * @param info
325
     * @param fqn of the containing class
326
     * @param simpleName of the method
327
     * @return true if {@code fqn.simpleName} represents a valid static method
328
     */
329
    public static boolean isValidStaticMethod(CompilationInfo info, String fqn, String simpleName) {
330
        TypeElement ie = info.getElements().getTypeElement(fqn);
331
        if (ie == null) {
332
            return false;
333
        }
334
        for (Element enclosed : ie.getEnclosedElements()) {
335
            Set<Modifier> modifiers = enclosed.getModifiers();
336
            if (enclosed.getKind() != ElementKind.METHOD || !modifiers.contains(Modifier.STATIC) || modifiers.contains(Modifier.PRIVATE)) {
337
                continue;
338
            }
339
            String sn1 = enclosed.getSimpleName().toString();
340
            if (simpleName.equals(sn1)) {
341
                return true;
342
            }
343
        }
344
        return false;
345
    }
346
}
(-)a/java.hints/src/org/netbeans/modules/java/hints/errors/ImportClass.java (-2 / +40 lines)
Lines 43-48 Link Here
43
43
44
import com.sun.source.tree.CompilationUnitTree;
44
import com.sun.source.tree.CompilationUnitTree;
45
import com.sun.source.tree.ImportTree;
45
import com.sun.source.tree.ImportTree;
46
import com.sun.source.tree.MemberSelectTree;
46
import com.sun.source.tree.MethodInvocationTree;
47
import com.sun.source.tree.MethodInvocationTree;
47
import com.sun.source.tree.Tree.Kind;
48
import com.sun.source.tree.Tree.Kind;
48
import com.sun.source.util.TreePath;
49
import com.sun.source.util.TreePath;
Lines 57-72 Link Here
57
import java.util.Set;
58
import java.util.Set;
58
import java.util.logging.Level;
59
import java.util.logging.Level;
59
import java.util.logging.Logger;
60
import java.util.logging.Logger;
61
import javax.lang.model.element.Element;
60
import javax.lang.model.element.TypeElement;
62
import javax.lang.model.element.TypeElement;
61
import org.netbeans.api.java.source.Task;
63
import org.netbeans.api.java.source.Task;
62
import org.netbeans.api.java.source.CompilationInfo;
64
import org.netbeans.api.java.source.CompilationInfo;
63
import org.netbeans.api.java.source.JavaSource;
65
import org.netbeans.api.java.source.JavaSource;
64
import org.netbeans.api.java.source.JavaSource.Phase;
66
import org.netbeans.api.java.source.JavaSource.Phase;
67
import org.netbeans.api.java.source.SourceUtils;
68
import org.netbeans.api.java.source.TreePathHandle;
65
import org.netbeans.api.java.source.WorkingCopy;
69
import org.netbeans.api.java.source.WorkingCopy;
66
import org.netbeans.api.lexer.Token;
70
import org.netbeans.api.lexer.Token;
67
import org.netbeans.modules.editor.java.Utilities;
71
import org.netbeans.modules.editor.java.Utilities;
68
import org.netbeans.modules.java.editor.imports.ComputeImports;
72
import org.netbeans.modules.java.editor.imports.ComputeImports;
69
import org.netbeans.modules.java.editor.imports.JavaFixAllImports;
73
import org.netbeans.modules.java.hints.StaticImport;
70
import org.netbeans.modules.java.hints.errors.ImportClass.ImportCandidatesHolder;
74
import org.netbeans.modules.java.hints.errors.ImportClass.ImportCandidatesHolder;
71
import org.netbeans.modules.java.hints.infrastructure.CreatorBasedLazyFixList;
75
import org.netbeans.modules.java.hints.infrastructure.CreatorBasedLazyFixList;
72
import org.netbeans.modules.java.hints.infrastructure.ErrorHintsProvider;
76
import org.netbeans.modules.java.hints.infrastructure.ErrorHintsProvider;
Lines 164-169 Link Here
164
        List<String> unfiltered = candidates.getB();
168
        List<String> unfiltered = candidates.getB();
165
        List<Fix> fixes = new ArrayList<Fix>();
169
        List<Fix> fixes = new ArrayList<Fix>();
166
        
170
        
171
        String staticSimpleName = null;
172
        TreePath mitPath = null;
173
        if (path.getLeaf().getKind() == Kind.IDENTIFIER) {
174
            TreePath parent = path.getParentPath();
175
            if (parent != null && parent.getLeaf().getKind() == Kind.MEMBER_SELECT) {
176
                mitPath = parent.getParentPath();
177
                if (mitPath != null && mitPath.getLeaf().getKind() == Kind.METHOD_INVOCATION) {
178
                    TreePath klass = StaticImport.getContainingClass(path);
179
                    Element klassElement = info.getTrees().getElement(klass);
180
                    // XXX why can't we use MemberSelectTree.getIdentifier
181
                    if (parent.getLeaf() instanceof MemberSelectTree) {
182
                        System.out.println("parent is MemberSelectTree");
183
                    } else {
184
                        System.out.println("parent is NOT a MemberSelectTree");
185
                    }
186
                    String ms = parent.getLeaf().toString();
187
                    int i = ms.lastIndexOf("."); // NOI18N
188
                    if (i != -1 && i < ms.length() - 2) {
189
                        String sn = ms.substring(i + 1);
190
                        if (!StaticImport.hasMethodNameClash(info, klassElement, sn) && !StaticImport.hasStaticImportSimpleNameClash(info, sn)) {
191
                            staticSimpleName = sn;
192
                        }
193
                    }
194
                }
195
            }
196
        }
197
167
        if (unfiltered != null && filtered != null) {
198
        if (unfiltered != null && filtered != null) {
168
            for (String fqn : unfiltered) {
199
            for (String fqn : unfiltered) {
169
                StringBuilder sort = new StringBuilder();
200
                StringBuilder sort = new StringBuilder();
Lines 186-191 Link Here
186
                sort.append(fqn);
217
                sort.append(fqn);
187
                
218
                
188
                fixes.add(new FixImport(file, fqn, sort.toString(), prefered));
219
                fixes.add(new FixImport(file, fqn, sort.toString(), prefered));
220
221
                if (staticSimpleName != null) {
222
                    String mFqn = fqn + "." + staticSimpleName; //NOI18N
223
                    if (StaticImport.isValidStaticMethod(info, fqn, staticSimpleName)) {
224
                        fixes.add(new StaticImport.FixImpl(TreePathHandle.create(mitPath, info), mFqn));
225
                    }
226
                }
189
            }
227
            }
190
        }
228
        }
191
        
229
        
Lines 340-346 Link Here
340
                            return ;
378
                            return ;
341
                        }
379
                        }
342
                        
380
                        
343
                        CompilationUnitTree cut = JavaFixAllImports.addImports(
381
                        CompilationUnitTree cut = SourceUtils.addImports(
344
                            copy.getCompilationUnit(),
382
                            copy.getCompilationUnit(),
345
                            Collections.singletonList(te.getQualifiedName().toString()),
383
                            Collections.singletonList(te.getQualifiedName().toString()),
346
                            copy.getTreeMaker()
384
                            copy.getTreeMaker()
(-)a/java.hints/src/org/netbeans/modules/java/hints/resources/layer.xml (+1 lines)
Lines 137-142 Link Here
137
                        <attr name="instanceCreate" methodvalue="org.netbeans.modules.java.hints.EqualsHint.getDelegate"/>
137
                        <attr name="instanceCreate" methodvalue="org.netbeans.modules.java.hints.EqualsHint.getDelegate"/>
138
                    </file>
138
                    </file>
139
                    <file name="org-netbeans-modules-java-hints-EqualsMethodHint.instance"/>
139
                    <file name="org-netbeans-modules-java-hints-EqualsMethodHint.instance"/>
140
                    <file name="org-netbeans-modules-java-hints-StaticImport.instance"/>
140
                    <file name="org-netbeans-modules-java-hints-SyncOnNonFinal.instance"/>
141
                    <file name="org-netbeans-modules-java-hints-SyncOnNonFinal.instance"/>
141
                    <file name="org-netbeans-modules-java-hints-CollectionRemove.instance"/>
142
                    <file name="org-netbeans-modules-java-hints-CollectionRemove.instance"/>
142
                </folder>
143
                </folder>
(-)a/java.source/src/org/netbeans/api/java/source/SourceUtils.java (-7 / +27 lines)
Lines 300-310 Link Here
300
    }
300
    }
301
    
301
    
302
    /**
302
    /**
303
     *
303
     * @param cut
304
     *
304
     * @param toImport
305
     * @param make
306
     * @return
307
     * @see #addStaticImports
305
     */
308
     */
306
    private static CompilationUnitTree addImports(CompilationUnitTree cut, List<String> toImport, TreeMaker make)
309
    public static CompilationUnitTree addImports(CompilationUnitTree cut, List<String> toImport, TreeMaker make) {
307
        throws IOException {
310
        return addImports(cut, toImport, make, false);
311
    }
312
313
    /**
314
     * @param cut
315
     * @param toImport
316
     * @param make
317
     * @return
318
     * @see #addImports
319
     */
320
    public static CompilationUnitTree addStaticImports(CompilationUnitTree cut, List<String> toImport, TreeMaker make) {
321
        return addImports(cut, toImport, make, true);
322
    }
323
324
    private static CompilationUnitTree addImports(CompilationUnitTree cut, List<String> toImport, TreeMaker make, boolean doStatic) {
325
        // XXX old (private) version claimed to throw IOException, but it didn't really.
308
        // do not modify the list given by the caller (may be reused or immutable).
326
        // do not modify the list given by the caller (may be reused or immutable).
309
        toImport = new ArrayList<String>(toImport); 
327
        toImport = new ArrayList<String>(toImport); 
310
        Collections.sort(toImport);
328
        Collections.sort(toImport);
Lines 316-326 Link Here
316
        while (currentToImport >= 0 && currentExisting >= 0) {
334
        while (currentToImport >= 0 && currentExisting >= 0) {
317
            String currentToImportText = toImport.get(currentToImport);
335
            String currentToImportText = toImport.get(currentToImport);
318
            
336
            
319
            while (currentExisting >= 0 && (imports.get(currentExisting).isStatic() || imports.get(currentExisting).getQualifiedIdentifier().toString().compareTo(currentToImportText) > 0))
337
            boolean ignore = (doStatic ^ imports.get(currentExisting).isStatic());
338
            while (currentExisting >= 0 && (ignore || imports.get(currentExisting).getQualifiedIdentifier().toString().compareTo(currentToImportText) > 0)) {
320
                currentExisting--;
339
                currentExisting--;
340
            }
321
            
341
            
322
            if (currentExisting >= 0) {
342
            if (currentExisting >= 0) {
323
                imports.add(currentExisting+1, make.Import(make.Identifier(currentToImportText), false));
343
                imports.add(currentExisting+1, make.Import(make.Identifier(currentToImportText), doStatic));
324
                currentToImport--;
344
                currentToImport--;
325
            }
345
            }
326
        }
346
        }
Lines 328-334 Link Here
328
        // to add, put them to the very beginning
348
        // to add, put them to the very beginning
329
        while (currentToImport >= 0) {
349
        while (currentToImport >= 0) {
330
            String importText = toImport.get(currentToImport);
350
            String importText = toImport.get(currentToImport);
331
            imports.add(0, make.Import(make.Identifier(importText), false));
351
            imports.add(0, make.Import(make.Identifier(importText), doStatic));
332
            currentToImport--;
352
            currentToImport--;
333
        }
353
        }
334
        // return a copy of the unit with changed imports section
354
        // return a copy of the unit with changed imports section

Return to bug 89258