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 191236
Collapse All | Expand All

(-)a/apisupport.project/src/org/netbeans/modules/apisupport/project/layers/LayerNode.java (-1 / +2 lines)
Lines 79-84 Link Here
79
import org.openide.util.RequestProcessor;
79
import org.openide.util.RequestProcessor;
80
import org.openide.util.actions.SystemAction;
80
import org.openide.util.actions.SystemAction;
81
import org.openide.util.lookup.Lookups;
81
import org.openide.util.lookup.Lookups;
82
import org.openide.util.lookup.ProxyLookup;
82
import org.openide.xml.XMLUtil;
83
import org.openide.xml.XMLUtil;
83
84
84
/**
85
/**
Lines 96-102 Link Here
96
    }
97
    }
97
    
98
    
98
    private LayerNode(Node delegate, LayerHandle handle, boolean specialDisplayName) {
99
    private LayerNode(Node delegate, LayerHandle handle, boolean specialDisplayName) {
99
        super(delegate, new LayerChildren(handle));
100
        super(delegate, new LayerChildren(handle), new ProxyLookup(delegate.getLookup(), Lookups.singleton(handle)));
100
        this.specialDisplayName = specialDisplayName;
101
        this.specialDisplayName = specialDisplayName;
101
    }
102
    }
102
    
103
    
(-)a/apisupport.refactoring/nbproject/project.xml (+36 lines)
Lines 50-55 Link Here
50
            <code-name-base>org.netbeans.modules.apisupport.refactoring</code-name-base>
50
            <code-name-base>org.netbeans.modules.apisupport.refactoring</code-name-base>
51
            <module-dependencies>
51
            <module-dependencies>
52
                <dependency>
52
                <dependency>
53
                    <code-name-base>org.netbeans.api.annotations.common</code-name-base>
54
                    <build-prerequisite/>
55
                    <compile-dependency/>
56
                    <run-dependency>
57
                        <release-version>1</release-version>
58
                        <specification-version>1.6</specification-version>
59
                    </run-dependency>
60
                </dependency>
61
                <dependency>
53
                    <code-name-base>org.netbeans.api.java</code-name-base>
62
                    <code-name-base>org.netbeans.api.java</code-name-base>
54
                    <build-prerequisite/>
63
                    <build-prerequisite/>
55
                    <compile-dependency/>
64
                    <compile-dependency/>
Lines 85-90 Link Here
85
                    </run-dependency>
94
                    </run-dependency>
86
                </dependency>
95
                </dependency>
87
                <dependency>
96
                <dependency>
97
                    <code-name-base>org.netbeans.modules.editor.errorstripe.api</code-name-base>
98
                    <build-prerequisite/>
99
                    <compile-dependency/>
100
                    <run-dependency>
101
                        <release-version>1</release-version>
102
                        <specification-version>2.14</specification-version>
103
                    </run-dependency>
104
                </dependency>
105
                <dependency>
106
                    <code-name-base>org.netbeans.modules.editor.mimelookup</code-name-base>
107
                    <build-prerequisite/>
108
                    <compile-dependency/>
109
                    <run-dependency>
110
                        <release-version>1</release-version>
111
                        <specification-version>1.20</specification-version>
112
                    </run-dependency>
113
                </dependency>
114
                <dependency>
88
                    <code-name-base>org.netbeans.modules.java.project</code-name-base>
115
                    <code-name-base>org.netbeans.modules.java.project</code-name-base>
89
                    <build-prerequisite/>
116
                    <build-prerequisite/>
90
                    <compile-dependency/>
117
                    <compile-dependency/>
Lines 137-142 Link Here
137
                    </run-dependency>
164
                    </run-dependency>
138
                </dependency>
165
                </dependency>
139
                <dependency>
166
                <dependency>
167
                    <code-name-base>org.netbeans.spi.editor.hints</code-name-base>
168
                    <build-prerequisite/>
169
                    <compile-dependency/>
170
                    <run-dependency>
171
                        <release-version>0</release-version>
172
                        <specification-version>1.15</specification-version>
173
                    </run-dependency>
174
                </dependency>
175
                <dependency>
140
                    <code-name-base>org.openide.filesystems</code-name-base>
176
                    <code-name-base>org.openide.filesystems</code-name-base>
141
                    <build-prerequisite/>
177
                    <build-prerequisite/>
142
                    <compile-dependency/>
178
                    <compile-dependency/>
(-)a/apisupport.refactoring/src/org/netbeans/modules/apisupport/hints/ActionRegistrationHinter.java (+84 lines)
Line 0 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * If you wish your version of this file to be governed by only the CDDL
28
 * or only the GPL Version 2, indicate your decision by adding
29
 * "[Contributor] elects to include this software in this distribution
30
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
31
 * single choice of license, a recipient has the option to distribute
32
 * your version of this file under either the CDDL, the GPL Version 2 or
33
 * to extend the choice of license to its licensees as provided above.
34
 * However, if you add GPL Version 2 code and therefore, elected the GPL
35
 * Version 2 license, then the option applies only if the new code is
36
 * made subject to such option by the copyright holder.
37
 *
38
 * Contributor(s):
39
 *
40
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
41
 */
42
43
package org.netbeans.modules.apisupport.hints;
44
45
import javax.lang.model.element.Element;
46
import javax.lang.model.element.ElementKind;
47
import javax.lang.model.element.ExecutableElement;
48
import javax.lang.model.element.TypeElement;
49
import org.netbeans.api.java.source.Task;
50
import org.netbeans.api.java.source.WorkingCopy;
51
import org.netbeans.spi.editor.hints.ChangeInfo;
52
import org.netbeans.spi.editor.hints.Fix;
53
import org.netbeans.spi.editor.hints.Severity;
54
import org.openide.util.lookup.ServiceProvider;
55
56
/**
57
 * Transformations for #183794: {@link org.openide.awt.ActionRegistration}
58
 */
59
@ServiceProvider(service=Hinter.class)
60
public class ActionRegistrationHinter implements Hinter {
61
62
    public @Override void process(final Context ctx) throws Exception {
63
        if ("method:org.openide.awt.Actions.alwaysEnabled".equals(ctx.instanceFile().getAttribute("literal:instanceCreate"))) {
64
            ctx.addHint(Severity.WARNING, /*XXX I18N*/"Use of layer entry where annotation is available", new Fix() {
65
                public @Override String getText() {
66
                    return "Convert registration to annotation";
67
                }
68
                public @Override ChangeInfo implement() throws Exception {
69
                    ctx.runModificationTask(new Task<WorkingCopy>() {
70
                        public @Override void run(WorkingCopy wc) throws Exception {
71
                            Element decl = ctx.findDeclaration(wc, ctx.instanceFile().getAttribute("literal:delegate"));
72
                            if (decl == null) {
73
                                return;
74
                            }
75
                            // XXX add @ActionRegistration, @ActionID, @ActionReference
76
                        }
77
                    });
78
                    return null;
79
                }
80
            });
81
        }
82
    }
83
84
}
(-)a/apisupport.refactoring/src/org/netbeans/modules/apisupport/hints/ConvertToAnnotationHint.java (+210 lines)
Line 0 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * If you wish your version of this file to be governed by only the CDDL
28
 * or only the GPL Version 2, indicate your decision by adding
29
 * "[Contributor] elects to include this software in this distribution
30
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
31
 * single choice of license, a recipient has the option to distribute
32
 * your version of this file under either the CDDL, the GPL Version 2 or
33
 * to extend the choice of license to its licensees as provided above.
34
 * However, if you add GPL Version 2 code and therefore, elected the GPL
35
 * Version 2 license, then the option applies only if the new code is
36
 * made subject to such option by the copyright holder.
37
 *
38
 * Contributor(s):
39
 *
40
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
41
 */
42
43
package org.netbeans.modules.apisupport.hints;
44
45
import java.util.ArrayList;
46
import java.util.HashMap;
47
import java.util.LinkedHashSet;
48
import java.util.List;
49
import java.util.Map;
50
import java.util.Set;
51
import javax.swing.text.Document;
52
import javax.xml.parsers.SAXParser;
53
import javax.xml.parsers.SAXParserFactory;
54
import org.netbeans.api.editor.mimelookup.MimeRegistration;
55
import org.netbeans.api.project.FileOwnerQuery;
56
import org.netbeans.api.project.Project;
57
import org.netbeans.modules.apisupport.project.api.LayerHandle;
58
import org.netbeans.modules.apisupport.project.spi.NbModuleProvider;
59
import org.netbeans.spi.editor.errorstripe.UpToDateStatus;
60
import org.netbeans.spi.editor.errorstripe.UpToDateStatusProvider;
61
import org.netbeans.spi.editor.errorstripe.UpToDateStatusProviderFactory;
62
import org.netbeans.spi.editor.hints.ErrorDescription;
63
import org.netbeans.spi.editor.hints.HintsController;
64
import org.openide.filesystems.FileChangeAdapter;
65
import org.openide.filesystems.FileChangeListener;
66
import org.openide.filesystems.FileEvent;
67
import org.openide.filesystems.FileObject;
68
import org.openide.filesystems.FileSystem;
69
import org.openide.filesystems.FileUtil;
70
import org.openide.loaders.DataObject;
71
import org.openide.loaders.DataObjectNotFoundException;
72
import org.openide.util.Exceptions;
73
import org.openide.util.Lookup;
74
import org.openide.util.NbCollections;
75
import org.openide.util.RequestProcessor;
76
import org.xml.sax.Attributes;
77
import org.xml.sax.InputSource;
78
import org.xml.sax.Locator;
79
import org.xml.sax.SAXException;
80
import org.xml.sax.ext.DefaultHandler2;
81
82
@MimeRegistration(mimeType="text/xml", service=UpToDateStatusProviderFactory.class)
83
public class ConvertToAnnotationHint implements UpToDateStatusProviderFactory {
84
85
    private static final RequestProcessor RP = new RequestProcessor(ConvertToAnnotationHint.class);
86
87
    public @Override UpToDateStatusProvider createUpToDateStatusProvider(Document doc) {
88
        Object sdp = doc.getProperty(Document.StreamDescriptionProperty); // avoid dep on NbEditorUtilities.getFileObject if possible
89
        DataObject xml;
90
        if (sdp instanceof DataObject) {
91
            xml = (DataObject) sdp;
92
        } else if (sdp instanceof FileObject) {
93
            try {
94
                xml = DataObject.find((FileObject) sdp);
95
            } catch (DataObjectNotFoundException x) {
96
                Exceptions.printStackTrace(x);
97
                return null;
98
            }
99
        } else {
100
            return null;
101
        }
102
        LayerHandle handle = xml.getNodeDelegate().getLookup().lookup(LayerHandle.class);
103
        if (handle == null) {
104
            return null;
105
        }
106
        Project project = FileOwnerQuery.getOwner(xml.getPrimaryFile());
107
        if (project == null || project.getLookup().lookup(NbModuleProvider.class) == null) {
108
            return null;
109
        }
110
        return new Prov(doc, xml, handle);
111
    }
112
113
    private static class Prov extends UpToDateStatusProvider implements Runnable {
114
115
        private final Document doc;
116
        private final LayerHandle handle;
117
        private boolean processed;
118
        private final FileChangeListener listener = new FileChangeAdapter() {
119
            public @Override void fileChanged(FileEvent fe) {
120
                processed = false;
121
                RP.post(Prov.this); // XXX use schedule on a Task
122
                firePropertyChange(PROP_UP_TO_DATE, null, null);
123
            }
124
        };
125
126
        Prov(Document doc, DataObject xml, LayerHandle handle) {
127
            this.doc = doc;
128
            this.handle = handle;
129
            xml.getPrimaryFile().addFileChangeListener(FileUtil.weakFileChangeListener(listener, xml.getPrimaryFile()));
130
            RP.post(this);
131
        }
132
133
        public @Override UpToDateStatus getUpToDate() {
134
            if (processed) {
135
                return UpToDateStatus.UP_TO_DATE_OK;
136
            }
137
            return processed ? UpToDateStatus.UP_TO_DATE_OK : UpToDateStatus.UP_TO_DATE_PROCESSING;
138
        }
139
140
        public @Override void run() {
141
            FileSystem fs = handle.layer(false);
142
            if (fs == null) {
143
                return;
144
            }
145
            Set<FileObject> instances = new LinkedHashSet<FileObject>();
146
            // Compare AbstractRefactoringPlugin.checkFileObject:
147
            FILE: for (FileObject f : NbCollections.iterable(fs.getRoot().getData(true))) {
148
                if (!f.hasExt("instance")) {
149
                    continue; // not supporting *.settings etc. for now
150
                }
151
                instances.add(f);
152
            }
153
            List<ErrorDescription> errors = new ArrayList<ErrorDescription>();
154
            if (!instances.isEmpty()) {
155
                final Map<String,Integer> lines = new HashMap<String,Integer>();
156
                try { // Adapted from OpenLayerFilesAction.openLayerFileAndFind:
157
                    InputSource in = new InputSource(handle.getLayerFile().getURL().toExternalForm());
158
                    SAXParserFactory factory = SAXParserFactory.newInstance();
159
                    SAXParser parser = factory.newSAXParser();
160
                    class Handler extends DefaultHandler2 {
161
                        private Locator locator;
162
                        private String path;
163
                        public @Override void setDocumentLocator(Locator l) {
164
                            locator = l;
165
                        }
166
                        public @Override void startElement(String uri, String localname, String qname, Attributes attr) throws SAXException {
167
                            if (!qname.matches("file|folder")) { // NOI18N
168
                                return;
169
                            }
170
                            String n = attr.getValue("name"); // NOI18N
171
                            path = path == null ? n : path + '/' + n;
172
                            lines.put(path, locator.getLineNumber());
173
                        }
174
                        public @Override void endElement(String uri, String localname, String qname) throws SAXException {
175
                            if (!qname.matches("file|folder")) { // NOI18N
176
                                return;
177
                            }
178
                            int slash = path.lastIndexOf('/');
179
                            path = slash == -1 ? null : path.substring(0, slash);
180
                        }
181
                    }
182
                    DefaultHandler2 handler = new Handler();
183
                    parser.getXMLReader().setProperty("http://xml.org/sax/properties/lexical-handler", handler); // NOI18N
184
                    parser.parse(in, handler);
185
                } catch (Exception x) {
186
                    Exceptions.printStackTrace(x);
187
                }
188
                for (FileObject instance : instances) {
189
                    Integer line = lines.get(instance.getPath());
190
                    if (line == null) {
191
                        System.err.println("XXX no line for " + instance.getPath());
192
                        continue;
193
                    }
194
                    for (Hinter hinter : Lookup.getDefault().lookupAll(Hinter.class)) {
195
                        try {
196
                            hinter.process(new Hinter.Context(doc, handle, instance, line, errors));
197
                        } catch (Exception x) {
198
                            Exceptions.printStackTrace(x);
199
                        }
200
                    }
201
               }
202
            }
203
            HintsController.setErrors(doc, ConvertToAnnotationHint.class.getName(), errors);
204
            processed = true;
205
            firePropertyChange(PROP_UP_TO_DATE, null, null);
206
        }
207
        
208
    }
209
210
}
(-)a/apisupport.refactoring/src/org/netbeans/modules/apisupport/hints/Hinter.java (+156 lines)
Line 0 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * If you wish your version of this file to be governed by only the CDDL
28
 * or only the GPL Version 2, indicate your decision by adding
29
 * "[Contributor] elects to include this software in this distribution
30
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
31
 * single choice of license, a recipient has the option to distribute
32
 * your version of this file under either the CDDL, the GPL Version 2 or
33
 * to extend the choice of license to its licensees as provided above.
34
 * However, if you add GPL Version 2 code and therefore, elected the GPL
35
 * Version 2 license, then the option applies only if the new code is
36
 * made subject to such option by the copyright holder.
37
 *
38
 * Contributor(s):
39
 *
40
 * Portions Copyrighted 2010 Sun Microsystems, Inc.
41
 */
42
43
package org.netbeans.modules.apisupport.hints;
44
45
import java.io.IOException;
46
import java.util.Arrays;
47
import java.util.List;
48
import javax.lang.model.element.Element;
49
import javax.lang.model.element.ElementKind;
50
import javax.lang.model.element.ExecutableElement;
51
import javax.lang.model.element.TypeElement;
52
import javax.swing.text.Document;
53
import org.netbeans.api.annotations.common.CheckForNull;
54
import org.netbeans.api.annotations.common.NullAllowed;
55
import org.netbeans.api.java.source.ClasspathInfo;
56
import org.netbeans.api.java.source.JavaSource;
57
import org.netbeans.api.java.source.Task;
58
import org.netbeans.api.java.source.WorkingCopy;
59
import org.netbeans.modules.apisupport.project.api.LayerHandle;
60
import org.netbeans.spi.editor.hints.ErrorDescription;
61
import org.netbeans.spi.editor.hints.ErrorDescriptionFactory;
62
import org.netbeans.spi.editor.hints.Fix;
63
import org.netbeans.spi.editor.hints.Severity;
64
import org.openide.filesystems.FileObject;
65
66
/**
67
 * One category of hint.
68
 * Register implementation into global lookup.
69
 */
70
public interface Hinter {
71
72
    /**
73
     * Check for hints.
74
     * @param ctx context of a single layer entry
75
     * @throws Exception in case of problem
76
     */
77
    void process(Context ctx) throws Exception;
78
79
    /**
80
     * Context supplied to a {@link Hinter}.
81
     */
82
    class Context {
83
84
        private final Document doc;
85
        private final LayerHandle layer;
86
        private final FileObject instanceFile;
87
        private final int line;
88
        private final List<? super ErrorDescription> errors;
89
90
        Context(Document doc, LayerHandle layer, FileObject instanceFile, int line, List<? super ErrorDescription> errors) {
91
            this.doc = doc;
92
            this.layer = layer;
93
            this.instanceFile = instanceFile;
94
            this.line = line;
95
            this.errors = errors;
96
        }
97
98
        /**
99
         * Gets the layer entry you may offer hints for.
100
         * File attribute names like {@code literal:instanceCreate} may return values like {@code new:pkg.Clazz} or {@code method:pkg.Clazz.factory}.
101
         * @return a {@code *.instance} file in the project's layer
102
         */
103
        public FileObject instanceFile() {
104
            return instanceFile;
105
        }
106
107
        /**
108
         * Add a hint.
109
         * @param severity whether to treat as a warning, etc.
110
         * @param description description of hint
111
         * @param fixes any fixes to offer
112
         */
113
        public void addHint(Severity severity, String description, Fix... fixes) {
114
            errors.add(ErrorDescriptionFactory.createErrorDescription(severity, description, Arrays.asList(fixes), doc, line));
115
        }
116
117
        /**
118
         * Runs (and commits) a Java source modification task in the context of the project with this layer.
119
         * @param task a task to run
120
         * @throws IOException if it could not be run
121
         */
122
        public void runModificationTask(Task<WorkingCopy> task) throws IOException {
123
            JavaSource.create(ClasspathInfo.create(layer.getLayerFile())).runModificationTask(task).commit();
124
        }
125
126
        /**
127
         * Locate the declaration of an object declared as a newvalue or methodvalue attribute.
128
         * @param wc as per {@link #runModificationTask}
129
         * @param instanceAttribute the result of {@link FileObject#getAttribute} on a {@code literal:*} key
130
         * @return the corresponding declaration, or null if not found
131
         */
132
        public @CheckForNull Element findDeclaration(WorkingCopy wc, @NullAllowed Object instanceAttribute) {
133
            if (!(instanceAttribute instanceof String)) {
134
                return null;
135
            }
136
            String attr = (String) instanceAttribute;
137
            if (attr.startsWith("new:")) {
138
                return wc.getElements().getTypeElement(attr.substring(4).replace('$', '.'));
139
            } else if (attr.startsWith("method:")) {
140
                int dot = attr.lastIndexOf('.');
141
                TypeElement type = wc.getElements().getTypeElement(attr.substring(7, dot).replace('$', '.'));
142
                if (type != null) {
143
                    String meth = attr.substring(dot + 1);
144
                    for (Element check : type.getEnclosedElements()) {
145
                        if (check.getKind() == ElementKind.METHOD && check.getSimpleName().contentEquals(meth) && ((ExecutableElement) check).getParameters().isEmpty()) {
146
                            return check;
147
                        }
148
                    }
149
                }
150
            }
151
            return null;
152
        }
153
154
    }
155
156
}

Return to bug 191236