c.s.tools.ide.analysis.modernize/src/com/sun/tools/ide/analysis/modernize/impl/ModernizeErrorProvider.java
author Ilia Gromov <ilia@netbeans.org>
Thu, 15 Jun 2017 13:26:38 +0300
branchrelease82
changeset 18425 4b288c339c55
parent 18415 35b6125ef00c
child 18426 76cdf4401581
permissions -rw-r--r--
[clang-tidy] merge analyser errors (only DEV compatible)
(transplanted from 853976f2c6166dbb19b482e2247ec824b7183371)
ilia@18415
     1
/*
ilia@18415
     2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
ilia@18415
     3
 *
ilia@18415
     4
 * Copyright (c) 2017 Oracle and/or its affiliates. All rights reserved.
ilia@18415
     5
 *
ilia@18415
     6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
ilia@18415
     7
 * Other names may be trademarks of their respective owners.
ilia@18415
     8
 *
ilia@18415
     9
 * The contents of this file are subject to the terms of either the GNU
ilia@18415
    10
 * General Public License Version 2 only ("GPL") or the Common
ilia@18415
    11
 * Development and Distribution License("CDDL") (collectively, the
ilia@18415
    12
 * "License"). You may not use this file except in compliance with the
ilia@18415
    13
 * License. You can obtain a copy of the License at
ilia@18415
    14
 * http://www.netbeans.org/cddl-gplv2.html
ilia@18415
    15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
ilia@18415
    16
 * specific language governing permissions and limitations under the
ilia@18415
    17
 * License.  When distributing the software, include this License Header
ilia@18415
    18
 * Notice in each file and include the License file at
ilia@18415
    19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
ilia@18415
    20
 * particular file as subject to the "Classpath" exception as provided
ilia@18415
    21
 * by Oracle in the GPL Version 2 section of the License file that
ilia@18415
    22
 * accompanied this code. If applicable, add the following below the
ilia@18415
    23
 * License Header, with the fields enclosed by brackets [] replaced by
ilia@18415
    24
 * your own identifying information:
ilia@18415
    25
 * "Portions Copyrighted [year] [name of copyright owner]"
ilia@18415
    26
 *
ilia@18415
    27
 * If you wish your version of this file to be governed by only the CDDL
ilia@18415
    28
 * or only the GPL Version 2, indicate your decision by adding
ilia@18415
    29
 * "[Contributor] elects to include this software in this distribution
ilia@18415
    30
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
ilia@18415
    31
 * single choice of license, a recipient has the option to distribute
ilia@18415
    32
 * your version of this file under either the CDDL, the GPL Version 2 or
ilia@18415
    33
 * to extend the choice of license to its licensees as provided above.
ilia@18415
    34
 * However, if you add GPL Version 2 code and therefore, elected the GPL
ilia@18415
    35
 * Version 2 license, then the option applies only if the new code is
ilia@18415
    36
 * made subject to such option by the copyright holder.
ilia@18415
    37
 *
ilia@18415
    38
 * Contributor(s): Ilia Gromov
ilia@18415
    39
 */
ilia@18415
    40
package com.sun.tools.ide.analysis.modernize.impl;
ilia@18415
    41
ilia@18415
    42
import com.sun.tools.ide.analysis.modernize.impl.YamlParser.Replacement;
ilia@18415
    43
import com.sun.tools.ide.analysis.modernize.options.AnalyzerPreferences;
ilia@18415
    44
import com.sun.tools.ide.analysis.modernize.options.ClangAnalyzerOptions;
ilia@18415
    45
import static com.sun.tools.ide.analysis.modernize.utils.AnalyticsTools.fatalError;
ilia@18415
    46
import static com.sun.tools.ide.analysis.modernize.utils.AnalyticsTools.findItem;
ilia@18415
    47
import java.io.File;
ilia@18415
    48
import java.io.IOException;
ilia@18415
    49
import java.util.ArrayList;
ilia@18415
    50
import java.util.Collection;
ilia@18415
    51
import java.util.Collections;
ilia@18415
    52
import java.util.List;
ilia@18415
    53
import java.util.logging.Level;
ilia@18415
    54
import java.util.logging.Logger;
ilia@18415
    55
import java.util.prefs.Preferences;
ilia@18415
    56
import javax.swing.JComponent;
ilia@18415
    57
import javax.swing.JLabel;
ilia@18415
    58
import org.netbeans.modules.cnd.analysis.api.AbstractCustomizerProvider;
ilia@18415
    59
import org.netbeans.modules.cnd.analysis.api.AnalyzerResponse;
ilia@18415
    60
import org.netbeans.modules.cnd.api.model.CsmFile;
ilia@18415
    61
import org.netbeans.modules.cnd.api.model.syntaxerr.AbstractCodeAudit;
ilia@18415
    62
import org.netbeans.modules.cnd.api.model.syntaxerr.AuditPreferences;
ilia@18415
    63
import org.netbeans.modules.cnd.api.model.syntaxerr.CodeAudit;
ilia@18415
    64
import org.netbeans.modules.cnd.api.model.syntaxerr.CodeAuditFactory;
ilia@18415
    65
import org.netbeans.modules.cnd.api.model.syntaxerr.CodeAuditProvider;
ilia@18415
    66
import org.netbeans.modules.cnd.api.model.syntaxerr.CsmErrorInfo;
ilia@18415
    67
import org.netbeans.modules.cnd.api.model.syntaxerr.CsmErrorInfo.Severity;
ilia@18415
    68
import org.netbeans.modules.cnd.api.model.syntaxerr.CsmErrorInfoHintProvider;
ilia@18415
    69
import org.netbeans.modules.cnd.api.model.syntaxerr.CsmErrorProvider;
ilia@18415
    70
import org.netbeans.modules.cnd.api.project.NativeFileItem.Language;
ilia@18415
    71
import org.netbeans.modules.cnd.api.project.NativeProject;
ilia@18415
    72
import org.netbeans.modules.cnd.api.remote.RemoteProject;
ilia@18415
    73
import org.netbeans.modules.cnd.makeproject.api.MakeProject;
ilia@18415
    74
import org.netbeans.modules.cnd.makeproject.api.configurations.Item;
ilia@18415
    75
import org.netbeans.modules.cnd.modelutil.CsmUtilities;
ilia@18415
    76
import org.netbeans.modules.cnd.utils.MIMENames;
ilia@18415
    77
import org.netbeans.modules.nativeexecution.api.ExecutionEnvironment;
ilia@18415
    78
import org.netbeans.modules.nativeexecution.api.ExecutionEnvironmentFactory;
ilia@18415
    79
import org.netbeans.modules.nativeexecution.api.util.ConnectionManager;
ilia@18417
    80
import org.netbeans.spi.editor.hints.ErrorDescription;
ilia@18415
    81
import org.netbeans.spi.editor.hints.Fix;
ilia@18415
    82
import org.openide.filesystems.FileObject;
ilia@18415
    83
import org.openide.filesystems.FileUtil;
ilia@18415
    84
import org.openide.util.Exceptions;
ilia@18415
    85
import org.openide.util.Lookup;
ilia@18415
    86
import org.openide.util.NbBundle;
ilia@18415
    87
import org.openide.util.lookup.ServiceProvider;
ilia@18415
    88
import org.openide.util.lookup.ServiceProviders;
ilia@18415
    89
ilia@18415
    90
@ServiceProviders({
ilia@18415
    91
    @ServiceProvider(service = CsmErrorProvider.class, position = 2100)
ilia@18415
    92
    ,
ilia@18415
    93
    @ServiceProvider(service = CodeAuditProvider.class, position = 2100)
ilia@18415
    94
})
ilia@18415
    95
public final class ModernizeErrorProvider extends CsmErrorProvider implements CodeAuditProvider, AbstractCustomizerProvider {
ilia@18415
    96
ilia@18415
    97
    public static final Logger LOG = Logger.getLogger("ide.analysis.tidy"); //NOI18N
ilia@18417
    98
    public static final String NAME = "Modernize"; //NOI18N
ilia@18417
    99
ilia@18415
   100
    private Collection<CodeAudit> audits;
ilia@18417
   101
    private AnalyzerResponseMerger analyzerResponseMerger;
ilia@18415
   102
ilia@18415
   103
    public static ModernizeErrorProvider getInstance() {
ilia@18415
   104
        for (CsmErrorProvider provider : Lookup.getDefault().lookupAll(CsmErrorProvider.class)) {
ilia@18415
   105
            if (NAME.equals(provider.getName()) && provider instanceof ModernizeErrorProvider) {
ilia@18415
   106
                return (ModernizeErrorProvider) provider;
ilia@18415
   107
            }
ilia@18415
   108
        }
ilia@18415
   109
        return null;
ilia@18415
   110
    }
ilia@18415
   111
ilia@18415
   112
    @Override
ilia@18415
   113
    protected boolean validate(Request request) {
ilia@18415
   114
        CsmFile file = request.getFile();
ilia@18415
   115
        return file != null;
ilia@18415
   116
    }
ilia@18415
   117
ilia@18415
   118
    @Override
ilia@18415
   119
    public boolean hasHintControlPanel() {
ilia@18415
   120
        return true;
ilia@18415
   121
    }
ilia@18415
   122
ilia@18415
   123
    @Override
ilia@18415
   124
    public String getName() {
ilia@18415
   125
        return NAME;
ilia@18415
   126
    }
ilia@18415
   127
ilia@18415
   128
    @Override
ilia@18415
   129
    public String getDisplayName() {
ilia@18415
   130
        return NbBundle.getMessage(ModernizeErrorProvider.class, "Modernize_NAME"); //NOI18N
ilia@18415
   131
    }
ilia@18415
   132
ilia@18415
   133
    @Override
ilia@18415
   134
    public String getDescription() {
ilia@18415
   135
        return NbBundle.getMessage(ModernizeErrorProvider.class, "Modernize_DESCRIPTION"); //NOI18N
ilia@18415
   136
    }
ilia@18415
   137
ilia@18415
   138
    @Override
ilia@18415
   139
    public String getMimeType() {
ilia@18415
   140
        return MIMENames.SOURCES_MIME_TYPE;
ilia@18415
   141
    }
ilia@18415
   142
ilia@18415
   143
    @Override
ilia@18415
   144
    public boolean isSupportedEvent(EditorEvent kind) {
ilia@18415
   145
        return kind == EditorEvent.FileBased;
ilia@18415
   146
    }
ilia@18415
   147
ilia@18415
   148
    @Override
ilia@18415
   149
    protected void doGetErrors(CsmErrorProvider.Request request, CsmErrorProvider.Response response) {
ilia@18415
   150
        CsmFile file = request.getFile();
ilia@18415
   151
        if (file != null) {
ilia@18415
   152
            if (request.isCancelled()) {
ilia@18415
   153
                return;
ilia@18415
   154
            }
ilia@18415
   155
            Object platformProject = file.getProject().getPlatformProject();
ilia@18415
   156
            if (platformProject instanceof NativeProject) {
ilia@18415
   157
                Lookup.Provider project = ((NativeProject) platformProject).getProject();
ilia@18415
   158
                if (project != null) {
ilia@18415
   159
                    if (request.isCancelled()) {
ilia@18415
   160
                        return;
ilia@18415
   161
                    }
ilia@18415
   162
                    Thread currentThread = Thread.currentThread();
ilia@18415
   163
                    currentThread.setName("Provider " + getName() + " prosess " + file.getAbsolutePath()); // NOI18N
ilia@18415
   164
                    RemoteProject info = project.getLookup().lookup(RemoteProject.class);
ilia@18415
   165
                    if (info != null) {
ilia@18415
   166
                        ExecutionEnvironment execEnv = info.getDevelopmentHost();
ilia@18415
   167
                        if (execEnv != null) {
ilia@18415
   168
                            if (request.isCancelled()) {
ilia@18415
   169
                                return;
ilia@18415
   170
                            }
ilia@18415
   171
                            if (ConnectionManager.getInstance().isConnectedTo(execEnv)) {
ilia@18415
   172
                                Item item = findItem(file, project);
ilia@18415
   173
                                if (item != null) {
ilia@18415
   174
                                    if (request.isCancelled()) {
ilia@18415
   175
                                        return;
ilia@18415
   176
                                    }
ilia@18415
   177
                                    // Temporarily analyzing even excluded items
ilia@18415
   178
                                    if (/* !item.isExcluded() &&  */(item.getLanguage() == Language.C || item.getLanguage() == Language.CPP || item.getLanguage() == Language.C_HEADER)) {
ilia@18415
   179
                                        analyze(execEnv, item, project, request, response);
ilia@18415
   180
                                    }
ilia@18415
   181
                                }
ilia@18415
   182
                            }
ilia@18415
   183
                        }
ilia@18415
   184
                    }
ilia@18415
   185
                }
ilia@18415
   186
            }
ilia@18415
   187
        }
ilia@18415
   188
    }
ilia@18415
   189
ilia@18415
   190
    public void analyze(ExecutionEnvironment execEnv, Item item, Lookup.Provider project, CsmErrorProvider.Request request, CsmErrorProvider.Response response) {
ilia@18415
   191
        String binaryPath = ClangAnalyzerOptions.getClangAnalyzerPath();
ilia@18417
   192
        boolean isAnalyzer = response instanceof ModernizeAnalyzerImpl.ModernizeResponse;
ilia@18415
   193
        if (binaryPath == null) {
ilia@18415
   194
            Level level = isAnalyzer ? Level.INFO : Level.FINE;
ilia@18415
   195
            LOG.log(level, "clang-tidy needs to be installed as a plugin"); //NOI18N
ilia@18415
   196
            return;
ilia@18415
   197
        }
ilia@18415
   198
ilia@18415
   199
        if (isAnalyzer && isNewRun()) {
ilia@18415
   200
            AnalyzedFiles.getDefault().clear();
ilia@18417
   201
            analyzerResponseMerger = new AnalyzerResponseMerger((ModernizeAnalyzerImpl.ModernizeResponse) response);
ilia@18415
   202
        }
ilia@18415
   203
ilia@18415
   204
        DiagnosticsTool diagnosticsTool = new DiagnosticsTool(execEnv, item, (MakeProject) project, binaryPath);
ilia@18415
   205
        try {
ilia@18415
   206
            CsmFile csmFile = request.getFile();
ilia@18415
   207
            Collection<String> checks = /*isAnalyzer ? Collections.singleton("*") : */ getEnabledChecks(); //NOI18N
ilia@18415
   208
ilia@18415
   209
            Collection<CsmFile> tu = new ArrayList<CsmFile>();
ilia@18415
   210
            if (isAnalyzer) {
ilia@18415
   211
                tu.add(csmFile);
ilia@18415
   212
            } else {
ilia@18415
   213
                if (AnalyzedFiles.getDefault().isStartFile(csmFile)) {
ilia@18415
   214
                    tu.add(csmFile);
ilia@18415
   215
                } else {
ilia@18415
   216
                    tu.addAll(AnalyzedFiles.getDefault().getStartFiles(csmFile));
ilia@18415
   217
                }
ilia@18415
   218
            }
ilia@18415
   219
ilia@18415
   220
            if (!isAnalyzer) {
ilia@18417
   221
                response = new CsmResponseMerger(response);
ilia@18415
   222
            }
ilia@18415
   223
ilia@18415
   224
            for (CsmFile startFile : tu) {
ilia@18415
   225
                int exitCode = diagnosticsTool.process(checks, startFile, true);
ilia@18415
   226
                if (exitCode != DiagnosticsTool.STATUS_OK) {
ilia@18415
   227
                    String error = NbBundle.getMessage(ModernizeErrorProvider.class, "compile.file.error"); //NOI18N
ilia@18415
   228
                    String info = NbBundle.getMessage(ModernizeErrorProvider.class, "compile.file.error.info", "" + exitCode); //NOI18N
ilia@18415
   229
                    fatalError(AnalyzerResponse.AnalyzerSeverity.FileError, "fatal.analyze.error", error + "\n" + info, csmFile, response); //NOI18N
ilia@18415
   230
                    return;
ilia@18415
   231
                }
ilia@18415
   232
                List<YamlParser.Diagnostics> results = YamlParser.getDefault().parseYaml(diagnosticsTool.getYamlAsString());
ilia@18415
   233
                postProcess(isAnalyzer, startFile, project, results, request, response);
ilia@18415
   234
            }
ilia@18415
   235
ilia@18415
   236
            if (!isAnalyzer) {
ilia@18415
   237
                response.done();
ilia@18415
   238
            }
ilia@18415
   239
ilia@18417
   240
        } catch (ConnectionManager.CancellationException | IOException ex) {
ilia@18415
   241
            Exceptions.printStackTrace(ex);
ilia@18415
   242
        }
ilia@18415
   243
    }
ilia@18415
   244
ilia@18415
   245
    private static CsmErrorProvider last;
ilia@18415
   246
ilia@18415
   247
    private boolean isNewRun() {
ilia@18415
   248
        if (last == null || this != last) {
ilia@18415
   249
            last = this;
ilia@18415
   250
            return true;
ilia@18415
   251
        }
ilia@18415
   252
        return false;
ilia@18415
   253
    }
ilia@18415
   254
ilia@18417
   255
    public Collection<ErrorDescription> done() {
ilia@18417
   256
        return analyzerResponseMerger.done();
ilia@18417
   257
    }
ilia@18417
   258
ilia@18415
   259
    public void postProcess(boolean isAnalyzer, CsmFile startFile, Lookup.Provider project, List<YamlParser.Diagnostics> results, CsmErrorProvider.Request request, CsmErrorProvider.Response response) {
ilia@18415
   260
        CsmFile file = request.getFile();
ilia@18417
   261
        List<CsmFile> otherCsmFiles = new ArrayList<>();
ilia@18415
   262
ilia@18415
   263
        for (YamlParser.Diagnostics diag : results) {
ilia@18415
   264
            // TODO: don't add "Configure Hint" fix multiple times for one line
ilia@18415
   265
            FileObject fo = FileUtil.toFileObject(new File(diag.getMessageFilePath()));
ilia@18415
   266
            CsmFile csmFile = CsmUtilities.getCsmFile(fo, false, false);
ilia@18415
   267
ilia@18415
   268
            // Composing a preview message. Showing a start file for compilation unit
ilia@18415
   269
            // in case we analysing a header file
ilia@18415
   270
            ModernizeErrorInfo info;
ilia@18415
   271
            if (startFile.equals(file) && csmFile.equals(file)) {
ilia@18415
   272
                String message = String.format("[%s]: %s", diag.getCheckName(), diag.getMessage()); //NOI18N
ilia@18415
   273
                info = ModernizeErrorInfo.withFixedMessage(diag, message, project);
ilia@18415
   274
            } else {
ilia@18415
   275
                info = ModernizeErrorInfo.withMutableMessage(diag, diag.getCheckName(), startFile.getName().toString(), diag.getMessage(), project);
ilia@18415
   276
            }
ilia@18415
   277
ilia@18415
   278
            if (isAnalyzer) {
ilia@18415
   279
                // Add found errors for all files (can be other files from compileUnit)
ilia@18417
   280
                analyzerResponseMerger.addError(info, fo);
ilia@18415
   281
ilia@18415
   282
                if (!csmFile.equals(file)) {
ilia@18415
   283
                    // May be not header (e.g BBB.cc: AAA.cc -> (includes) BBB.cc -> ... )
ilia@18415
   284
                    otherCsmFiles.add(csmFile);
ilia@18415
   285
                }
ilia@18415
   286
            } else if (fo.equals(file.getFileObject())) {
ilia@18415
   287
                // Add found errors only for file displayed in Editor
ilia@18415
   288
                response.addError(info);
ilia@18415
   289
            }
ilia@18415
   290
        }
ilia@18415
   291
ilia@18415
   292
        if (isAnalyzer /* and not empty? */) {
ilia@18415
   293
            AnalyzedFiles.getDefault().cacheHierarchy(file, otherCsmFiles);
ilia@18415
   294
        }
ilia@18415
   295
    }
ilia@18415
   296
ilia@18415
   297
    @ServiceProvider(path = CodeAuditFactory.REGISTRATION_PATH + ModernizeErrorProvider.NAME, service = CodeAuditFactory.class, position = 4000)
ilia@18415
   298
    public static final class Factory implements CodeAuditFactory {
ilia@18415
   299
ilia@18415
   300
        @Override
ilia@18415
   301
        public AbstractCodeAudit create(AuditPreferences preferences) {
ilia@18415
   302
            String id = NbBundle.getMessage(ModernizeCodeAudit.class, "LBL_ProviderName");  // NOI18N
ilia@18415
   303
            String description = NbBundle.getMessage(ModernizeCodeAudit.class, "LBL_ProviderDescription");  // NOI18N
ilia@18415
   304
            return new ModernizeCodeAudit(id, id, description, "error", false, preferences);  // NOI18N
ilia@18415
   305
        }
ilia@18415
   306
    }
ilia@18415
   307
ilia@18415
   308
    private String oldPath;
ilia@18415
   309
ilia@18415
   310
    @Override
ilia@18415
   311
    public synchronized Collection<CodeAudit> getAudits() {
ilia@18415
   312
        String path = ClangAnalyzerOptions.getClangAnalyzerPath();
ilia@18415
   313
ilia@18415
   314
        if (path == null) {
ilia@18415
   315
            return Collections.emptyList();
ilia@18415
   316
        }
ilia@18415
   317
ilia@18415
   318
        if (oldPath == null) {
ilia@18415
   319
            oldPath = path;
ilia@18415
   320
        }
ilia@18415
   321
ilia@18415
   322
        if (audits == null || !oldPath.equals(path)) {
ilia@18415
   323
            List<CodeAudit> res = DiagnosticsTool.getAudits(path, ExecutionEnvironmentFactory.getLocal(), AnalyzerPreferences.getAuditPreferences());
ilia@18415
   324
ilia@18415
   325
            audits = res;
ilia@18415
   326
            oldPath = path;
ilia@18415
   327
        }
ilia@18415
   328
        return audits;
ilia@18415
   329
    }
ilia@18415
   330
ilia@18415
   331
    public Collection<String> getEnabledChecks() {
ilia@18415
   332
        Collection<CodeAudit> auditList = getAudits();
ilia@18415
   333
        List<String> enabled = new ArrayList<String>();
ilia@18415
   334
        for (CodeAudit codeAudit : auditList) {
ilia@18415
   335
            if (codeAudit.isEnabled()) {
ilia@18415
   336
                enabled.add(codeAudit.getID());
ilia@18415
   337
            }
ilia@18415
   338
        }
ilia@18415
   339
        return enabled.size() == auditList.size() ? Collections.singleton("*") : enabled; //NOI18N
ilia@18415
   340
    }
ilia@18415
   341
ilia@18415
   342
    @Override
ilia@18415
   343
    public AuditPreferences getPreferences() {
ilia@18415
   344
        return AnalyzerPreferences.getAuditPreferences();
ilia@18415
   345
    }
ilia@18415
   346
ilia@18415
   347
    @Override
ilia@18415
   348
    public JComponent createComponent(Preferences context) {
ilia@18415
   349
        return new JLabel();
ilia@18415
   350
    }
ilia@18415
   351
ilia@18415
   352
    public static interface ErrorInfoWithId {
ilia@18415
   353
ilia@18415
   354
        String getId();
ilia@18415
   355
    }
ilia@18415
   356
ilia@18415
   357
    public static final class FatalErrorInfo implements CsmErrorInfo, ErrorInfoWithId {
ilia@18415
   358
ilia@18415
   359
        private final String id;
ilia@18415
   360
        private final String message;
ilia@18415
   361
ilia@18415
   362
        public FatalErrorInfo(String id, String message) {
ilia@18415
   363
            this.id = id;
ilia@18415
   364
            this.message = message;
ilia@18415
   365
        }
ilia@18415
   366
ilia@18415
   367
        @Override
ilia@18415
   368
        public String getMessage() {
ilia@18415
   369
            return message;
ilia@18415
   370
        }
ilia@18415
   371
ilia@18415
   372
        @Override
ilia@18415
   373
        public Severity getSeverity() {
ilia@18415
   374
            return Severity.WARNING;
ilia@18415
   375
        }
ilia@18415
   376
ilia@18415
   377
        @Override
ilia@18415
   378
        public int getStartOffset() {
ilia@18415
   379
            return 0;
ilia@18415
   380
        }
ilia@18415
   381
ilia@18415
   382
        @Override
ilia@18415
   383
        public int getEndOffset() {
ilia@18415
   384
            return 1;
ilia@18415
   385
        }
ilia@18415
   386
ilia@18415
   387
        @Override
ilia@18415
   388
        public String getId() {
ilia@18415
   389
            return id;
ilia@18415
   390
        }
ilia@18415
   391
    }
ilia@18415
   392
ilia@18415
   393
    @ServiceProvider(service = CsmErrorInfoHintProvider.class, position = 9100)
ilia@18415
   394
    public final static class ModerinzeHintProvider extends CsmErrorInfoHintProvider {
ilia@18415
   395
ilia@18415
   396
        @Override
ilia@18415
   397
        protected List<Fix> doGetFixes(CsmErrorInfo info, List<Fix> alreadyFound) {
ilia@18415
   398
            if (info instanceof ModernizeErrorInfo) {
ilia@18415
   399
                alreadyFound.add(new ConfigureHintsFix((ModernizeErrorInfo) info));
ilia@18415
   400
            }
ilia@18415
   401
            return alreadyFound;
ilia@18415
   402
        }
ilia@18415
   403
    }
ilia@18415
   404
ilia@18415
   405
    @ServiceProvider(service = CsmErrorInfoHintProvider.class, position = 1600)
ilia@18415
   406
    public static final class ModernizeFixProvider extends CsmErrorInfoHintProvider {
ilia@18415
   407
ilia@18415
   408
        @Override
ilia@18415
   409
        protected List<Fix> doGetFixes(CsmErrorInfo info, List<Fix> alreadyFound) {
ilia@18415
   410
            alreadyFound.addAll(createFixes(info));
ilia@18415
   411
            return alreadyFound;
ilia@18415
   412
        }
ilia@18415
   413
    }
ilia@18415
   414
ilia@18415
   415
    private static List<? extends Fix> createFixes(CsmErrorInfo info) {
ilia@18415
   416
        if (info instanceof ModernizeErrorInfo) {
ilia@18415
   417
            ModernizeErrorInfo mei = (ModernizeErrorInfo) info;
ilia@18415
   418
            List<Replacement> replacements = mei.getDiagnostics().getReplacements();
ilia@18415
   419
            if (!replacements.isEmpty()) {
ilia@18415
   420
                return Collections.singletonList(new ModernizeFix(replacements, mei.getId()));
ilia@18415
   421
            }
ilia@18415
   422
        }
ilia@18415
   423
        return Collections.EMPTY_LIST;
ilia@18415
   424
    }
ilia@18415
   425
}