c.s.tools.ide.analysis.modernize/src/com/sun/tools/ide/analysis/modernize/impl/ModernizeErrorProvider.java
author Ilia Gromov <ilia@netbeans.org>
Wed, 07 Jun 2017 20:23:29 +0300
branchrelease82
changeset 18423 b9d9af239a0c
child 18417 853976f2c616
permissions -rw-r--r--
Fixing #270763 - Move clang-tidy integration to nb contrib
* * *
Fixing #270763 - Move clang-tidy integration to nb contrib - move wrapper
* * *
Fixing #270763 - Move clang-tidy integration to nb contrib - sign nbm
* * *
Fixing #270763 - Move clang-tidy integration to nb contrib - move tests
* * *
Fixing #270763 - Move clang-tidy integration to nb contrib - data for a new test
* * *
Fixed #270839 - [clang-tidy] Group checks in Editor hints
(transplanted from 35b6125ef00c470655dac6673075f5c12ec74593)
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.ModernizeAnalyzerImpl.ResponseImpl;
ilia@18415
    43
import com.sun.tools.ide.analysis.modernize.impl.YamlParser.Replacement;
ilia@18415
    44
import com.sun.tools.ide.analysis.modernize.options.AnalyzerPreferences;
ilia@18415
    45
import com.sun.tools.ide.analysis.modernize.options.ClangAnalyzerOptions;
ilia@18415
    46
import static com.sun.tools.ide.analysis.modernize.utils.AnalyticsTools.fatalError;
ilia@18415
    47
import static com.sun.tools.ide.analysis.modernize.utils.AnalyticsTools.findItem;
ilia@18415
    48
import java.io.File;
ilia@18415
    49
import java.io.IOException;
ilia@18415
    50
import java.util.ArrayList;
ilia@18415
    51
import java.util.Collection;
ilia@18415
    52
import java.util.Collections;
ilia@18415
    53
import java.util.List;
ilia@18415
    54
import java.util.logging.Level;
ilia@18415
    55
import java.util.logging.Logger;
ilia@18415
    56
import java.util.prefs.Preferences;
ilia@18415
    57
import javax.swing.JComponent;
ilia@18415
    58
import javax.swing.JLabel;
ilia@18415
    59
import org.netbeans.modules.cnd.analysis.api.AbstractCustomizerProvider;
ilia@18415
    60
import org.netbeans.modules.cnd.analysis.api.AnalyzerResponse;
ilia@18415
    61
import org.netbeans.modules.cnd.api.model.CsmFile;
ilia@18415
    62
import org.netbeans.modules.cnd.api.model.syntaxerr.AbstractCodeAudit;
ilia@18415
    63
import org.netbeans.modules.cnd.api.model.syntaxerr.AuditPreferences;
ilia@18415
    64
import org.netbeans.modules.cnd.api.model.syntaxerr.CodeAudit;
ilia@18415
    65
import org.netbeans.modules.cnd.api.model.syntaxerr.CodeAuditFactory;
ilia@18415
    66
import org.netbeans.modules.cnd.api.model.syntaxerr.CodeAuditProvider;
ilia@18415
    67
import org.netbeans.modules.cnd.api.model.syntaxerr.CsmErrorInfo;
ilia@18415
    68
import org.netbeans.modules.cnd.api.model.syntaxerr.CsmErrorInfo.Severity;
ilia@18415
    69
import org.netbeans.modules.cnd.api.model.syntaxerr.CsmErrorInfoHintProvider;
ilia@18415
    70
import org.netbeans.modules.cnd.api.model.syntaxerr.CsmErrorProvider;
ilia@18415
    71
import org.netbeans.modules.cnd.api.project.NativeFileItem.Language;
ilia@18415
    72
import org.netbeans.modules.cnd.api.project.NativeProject;
ilia@18415
    73
import org.netbeans.modules.cnd.api.remote.RemoteProject;
ilia@18415
    74
import org.netbeans.modules.cnd.makeproject.api.MakeProject;
ilia@18415
    75
import org.netbeans.modules.cnd.makeproject.api.configurations.Item;
ilia@18415
    76
import org.netbeans.modules.cnd.modelutil.CsmUtilities;
ilia@18415
    77
import org.netbeans.modules.cnd.utils.MIMENames;
ilia@18415
    78
import org.netbeans.modules.nativeexecution.api.ExecutionEnvironment;
ilia@18415
    79
import org.netbeans.modules.nativeexecution.api.ExecutionEnvironmentFactory;
ilia@18415
    80
import org.netbeans.modules.nativeexecution.api.util.ConnectionManager;
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@18415
    98
    private Collection<CodeAudit> audits;
ilia@18415
    99
    public static final String NAME = "Modernize"; //NOI18N
ilia@18415
   100
ilia@18415
   101
    public static ModernizeErrorProvider getInstance() {
ilia@18415
   102
        for (CsmErrorProvider provider : Lookup.getDefault().lookupAll(CsmErrorProvider.class)) {
ilia@18415
   103
            if (NAME.equals(provider.getName()) && provider instanceof ModernizeErrorProvider) {
ilia@18415
   104
                return (ModernizeErrorProvider) provider;
ilia@18415
   105
            }
ilia@18415
   106
        }
ilia@18415
   107
        return null;
ilia@18415
   108
    }
ilia@18415
   109
ilia@18415
   110
    @Override
ilia@18415
   111
    protected boolean validate(Request request) {
ilia@18415
   112
        CsmFile file = request.getFile();
ilia@18415
   113
        return file != null;
ilia@18415
   114
    }
ilia@18415
   115
ilia@18415
   116
    @Override
ilia@18415
   117
    public boolean hasHintControlPanel() {
ilia@18415
   118
        return true;
ilia@18415
   119
    }
ilia@18415
   120
ilia@18415
   121
    @Override
ilia@18415
   122
    public String getName() {
ilia@18415
   123
        return NAME;
ilia@18415
   124
    }
ilia@18415
   125
ilia@18415
   126
    @Override
ilia@18415
   127
    public String getDisplayName() {
ilia@18415
   128
        return NbBundle.getMessage(ModernizeErrorProvider.class, "Modernize_NAME"); //NOI18N
ilia@18415
   129
    }
ilia@18415
   130
ilia@18415
   131
    @Override
ilia@18415
   132
    public String getDescription() {
ilia@18415
   133
        return NbBundle.getMessage(ModernizeErrorProvider.class, "Modernize_DESCRIPTION"); //NOI18N
ilia@18415
   134
    }
ilia@18415
   135
ilia@18415
   136
    @Override
ilia@18415
   137
    public String getMimeType() {
ilia@18415
   138
        return MIMENames.SOURCES_MIME_TYPE;
ilia@18415
   139
    }
ilia@18415
   140
ilia@18415
   141
    @Override
ilia@18415
   142
    public boolean isSupportedEvent(EditorEvent kind) {
ilia@18415
   143
        return kind == EditorEvent.FileBased;
ilia@18415
   144
    }
ilia@18415
   145
ilia@18415
   146
    @Override
ilia@18415
   147
    protected void doGetErrors(CsmErrorProvider.Request request, CsmErrorProvider.Response response) {
ilia@18415
   148
        CsmFile file = request.getFile();
ilia@18415
   149
        if (file != null) {
ilia@18415
   150
            if (request.isCancelled()) {
ilia@18415
   151
                return;
ilia@18415
   152
            }
ilia@18415
   153
            Object platformProject = file.getProject().getPlatformProject();
ilia@18415
   154
            if (platformProject instanceof NativeProject) {
ilia@18415
   155
                Lookup.Provider project = ((NativeProject) platformProject).getProject();
ilia@18415
   156
                if (project != null) {
ilia@18415
   157
                    if (request.isCancelled()) {
ilia@18415
   158
                        return;
ilia@18415
   159
                    }
ilia@18415
   160
                    Thread currentThread = Thread.currentThread();
ilia@18415
   161
                    currentThread.setName("Provider " + getName() + " prosess " + file.getAbsolutePath()); // NOI18N
ilia@18415
   162
                    RemoteProject info = project.getLookup().lookup(RemoteProject.class);
ilia@18415
   163
                    if (info != null) {
ilia@18415
   164
                        ExecutionEnvironment execEnv = info.getDevelopmentHost();
ilia@18415
   165
                        if (execEnv != null) {
ilia@18415
   166
                            if (request.isCancelled()) {
ilia@18415
   167
                                return;
ilia@18415
   168
                            }
ilia@18415
   169
                            if (ConnectionManager.getInstance().isConnectedTo(execEnv)) {
ilia@18415
   170
                                Item item = findItem(file, project);
ilia@18415
   171
                                if (item != null) {
ilia@18415
   172
                                    if (request.isCancelled()) {
ilia@18415
   173
                                        return;
ilia@18415
   174
                                    }
ilia@18415
   175
                                    // Temporarily analyzing even excluded items
ilia@18415
   176
                                    if (/* !item.isExcluded() &&  */(item.getLanguage() == Language.C || item.getLanguage() == Language.CPP || item.getLanguage() == Language.C_HEADER)) {
ilia@18415
   177
                                        analyze(execEnv, item, project, request, response);
ilia@18415
   178
                                    }
ilia@18415
   179
                                }
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
    public void analyze(ExecutionEnvironment execEnv, Item item, Lookup.Provider project, CsmErrorProvider.Request request, CsmErrorProvider.Response response) {
ilia@18415
   189
        String binaryPath = ClangAnalyzerOptions.getClangAnalyzerPath();
ilia@18415
   190
        boolean isAnalyzer = response instanceof ModernizeAnalyzerImpl.ResponseImpl;
ilia@18415
   191
        if (binaryPath == null) {
ilia@18415
   192
            Level level = isAnalyzer ? Level.INFO : Level.FINE;
ilia@18415
   193
            LOG.log(level, "clang-tidy needs to be installed as a plugin"); //NOI18N
ilia@18415
   194
            return;
ilia@18415
   195
        }
ilia@18415
   196
ilia@18415
   197
        if (isAnalyzer && isNewRun()) {
ilia@18415
   198
            AnalyzedFiles.getDefault().clear();
ilia@18415
   199
        }
ilia@18415
   200
ilia@18415
   201
        DiagnosticsTool diagnosticsTool = new DiagnosticsTool(execEnv, item, (MakeProject) project, binaryPath);
ilia@18415
   202
        try {
ilia@18415
   203
            CsmFile csmFile = request.getFile();
ilia@18415
   204
            Collection<String> checks = /*isAnalyzer ? Collections.singleton("*") : */ getEnabledChecks(); //NOI18N
ilia@18415
   205
ilia@18415
   206
            Collection<CsmFile> tu = new ArrayList<CsmFile>();
ilia@18415
   207
            if (isAnalyzer) {
ilia@18415
   208
                tu.add(csmFile);
ilia@18415
   209
            } else {
ilia@18415
   210
                if (AnalyzedFiles.getDefault().isStartFile(csmFile)) {
ilia@18415
   211
                    tu.add(csmFile);
ilia@18415
   212
                } else {
ilia@18415
   213
                    tu.addAll(AnalyzedFiles.getDefault().getStartFiles(csmFile));
ilia@18415
   214
                }
ilia@18415
   215
            }
ilia@18415
   216
ilia@18415
   217
            if (!isAnalyzer) {
ilia@18415
   218
                response = new ResponseMerger(response);
ilia@18415
   219
            }
ilia@18415
   220
ilia@18415
   221
            for (CsmFile startFile : tu) {
ilia@18415
   222
                int exitCode = diagnosticsTool.process(checks, startFile, true);
ilia@18415
   223
                if (exitCode != DiagnosticsTool.STATUS_OK) {
ilia@18415
   224
                    String error = NbBundle.getMessage(ModernizeErrorProvider.class, "compile.file.error"); //NOI18N
ilia@18415
   225
                    String info = NbBundle.getMessage(ModernizeErrorProvider.class, "compile.file.error.info", "" + exitCode); //NOI18N
ilia@18415
   226
                    fatalError(AnalyzerResponse.AnalyzerSeverity.FileError, "fatal.analyze.error", error + "\n" + info, csmFile, response); //NOI18N
ilia@18415
   227
                    return;
ilia@18415
   228
                }
ilia@18415
   229
                List<YamlParser.Diagnostics> results = YamlParser.getDefault().parseYaml(diagnosticsTool.getYamlAsString());
ilia@18415
   230
                postProcess(isAnalyzer, startFile, project, results, request, response);
ilia@18415
   231
            }
ilia@18415
   232
ilia@18415
   233
            if (!isAnalyzer) {
ilia@18415
   234
                response.done();
ilia@18415
   235
            }
ilia@18415
   236
ilia@18415
   237
        } catch (ConnectionManager.CancellationException ex) {
ilia@18415
   238
            Exceptions.printStackTrace(ex);
ilia@18415
   239
        } catch (IOException ex) {
ilia@18415
   240
            Exceptions.printStackTrace(ex);
ilia@18415
   241
        }
ilia@18415
   242
    }
ilia@18415
   243
ilia@18415
   244
    private static CsmErrorProvider last;
ilia@18415
   245
ilia@18415
   246
    private boolean isNewRun() {
ilia@18415
   247
        if (last == null || this != last) {
ilia@18415
   248
            last = this;
ilia@18415
   249
            return true;
ilia@18415
   250
        }
ilia@18415
   251
        return false;
ilia@18415
   252
    }
ilia@18415
   253
ilia@18415
   254
    public void postProcess(boolean isAnalyzer, CsmFile startFile, Lookup.Provider project, List<YamlParser.Diagnostics> results, CsmErrorProvider.Request request, CsmErrorProvider.Response response) {
ilia@18415
   255
        CsmFile file = request.getFile();
ilia@18415
   256
        List<CsmFile> otherCsmFiles = new ArrayList<CsmFile>();
ilia@18415
   257
ilia@18415
   258
        for (YamlParser.Diagnostics diag : results) {
ilia@18415
   259
            // TODO: don't add "Configure Hint" fix multiple times for one line
ilia@18415
   260
            FileObject fo = FileUtil.toFileObject(new File(diag.getMessageFilePath()));
ilia@18415
   261
            CsmFile csmFile = CsmUtilities.getCsmFile(fo, false, false);
ilia@18415
   262
ilia@18415
   263
            // Composing a preview message. Showing a start file for compilation unit
ilia@18415
   264
            // in case we analysing a header file
ilia@18415
   265
            ModernizeErrorInfo info;
ilia@18415
   266
            if (startFile.equals(file) && csmFile.equals(file)) {
ilia@18415
   267
                String message = String.format("[%s]: %s", diag.getCheckName(), diag.getMessage()); //NOI18N
ilia@18415
   268
                info = ModernizeErrorInfo.withFixedMessage(diag, message, project);
ilia@18415
   269
            } else {
ilia@18415
   270
                info = ModernizeErrorInfo.withMutableMessage(diag, diag.getCheckName(), startFile.getName().toString(), diag.getMessage(), project);
ilia@18415
   271
            }
ilia@18415
   272
ilia@18415
   273
            if (isAnalyzer) {
ilia@18415
   274
                // Add found errors for all files (can be other files from compileUnit)
ilia@18415
   275
                ((ResponseImpl) response).addError(AnalyzerResponse.AnalyzerSeverity.DetectedError, null, fo, info);
ilia@18415
   276
ilia@18415
   277
                if (!csmFile.equals(file)) {
ilia@18415
   278
                    // May be not header (e.g BBB.cc: AAA.cc -> (includes) BBB.cc -> ... )
ilia@18415
   279
                    otherCsmFiles.add(csmFile);
ilia@18415
   280
                }
ilia@18415
   281
            } else if (fo.equals(file.getFileObject())) {
ilia@18415
   282
                // Add found errors only for file displayed in Editor
ilia@18415
   283
                response.addError(info);
ilia@18415
   284
            }
ilia@18415
   285
        }
ilia@18415
   286
ilia@18415
   287
        if (isAnalyzer /* and not empty? */) {
ilia@18415
   288
            AnalyzedFiles.getDefault().cacheHierarchy(file, otherCsmFiles);
ilia@18415
   289
        }
ilia@18415
   290
    }
ilia@18415
   291
ilia@18415
   292
    @ServiceProvider(path = CodeAuditFactory.REGISTRATION_PATH + ModernizeErrorProvider.NAME, service = CodeAuditFactory.class, position = 4000)
ilia@18415
   293
    public static final class Factory implements CodeAuditFactory {
ilia@18415
   294
ilia@18415
   295
        @Override
ilia@18415
   296
        public AbstractCodeAudit create(AuditPreferences preferences) {
ilia@18415
   297
            String id = NbBundle.getMessage(ModernizeCodeAudit.class, "LBL_ProviderName");  // NOI18N
ilia@18415
   298
            String description = NbBundle.getMessage(ModernizeCodeAudit.class, "LBL_ProviderDescription");  // NOI18N
ilia@18415
   299
            return new ModernizeCodeAudit(id, id, description, "error", false, preferences);  // NOI18N
ilia@18415
   300
        }
ilia@18415
   301
    }
ilia@18415
   302
ilia@18415
   303
    private String oldPath;
ilia@18415
   304
ilia@18415
   305
    @Override
ilia@18415
   306
    public synchronized Collection<CodeAudit> getAudits() {
ilia@18415
   307
        String path = ClangAnalyzerOptions.getClangAnalyzerPath();
ilia@18415
   308
ilia@18415
   309
        if (path == null) {
ilia@18415
   310
            return Collections.emptyList();
ilia@18415
   311
        }
ilia@18415
   312
ilia@18415
   313
        if (oldPath == null) {
ilia@18415
   314
            oldPath = path;
ilia@18415
   315
        }
ilia@18415
   316
ilia@18415
   317
        if (audits == null || !oldPath.equals(path)) {
ilia@18415
   318
            List<CodeAudit> res = DiagnosticsTool.getAudits(path, ExecutionEnvironmentFactory.getLocal(), AnalyzerPreferences.getAuditPreferences());
ilia@18415
   319
ilia@18415
   320
            audits = res;
ilia@18415
   321
            oldPath = path;
ilia@18415
   322
        }
ilia@18415
   323
        return audits;
ilia@18415
   324
    }
ilia@18415
   325
ilia@18415
   326
    public Collection<String> getEnabledChecks() {
ilia@18415
   327
        Collection<CodeAudit> auditList = getAudits();
ilia@18415
   328
        List<String> enabled = new ArrayList<String>();
ilia@18415
   329
        for (CodeAudit codeAudit : auditList) {
ilia@18415
   330
            if (codeAudit.isEnabled()) {
ilia@18415
   331
                enabled.add(codeAudit.getID());
ilia@18415
   332
            }
ilia@18415
   333
        }
ilia@18415
   334
        return enabled.size() == auditList.size() ? Collections.singleton("*") : enabled; //NOI18N
ilia@18415
   335
    }
ilia@18415
   336
ilia@18415
   337
    @Override
ilia@18415
   338
    public AuditPreferences getPreferences() {
ilia@18415
   339
        return AnalyzerPreferences.getAuditPreferences();
ilia@18415
   340
    }
ilia@18415
   341
ilia@18415
   342
    @Override
ilia@18415
   343
    public JComponent createComponent(Preferences context) {
ilia@18415
   344
        return new JLabel();
ilia@18415
   345
    }
ilia@18415
   346
ilia@18415
   347
    public static interface ErrorInfoWithId {
ilia@18415
   348
ilia@18415
   349
        String getId();
ilia@18415
   350
    }
ilia@18415
   351
ilia@18415
   352
    public static final class FatalErrorInfo implements CsmErrorInfo, ErrorInfoWithId {
ilia@18415
   353
ilia@18415
   354
        private final String id;
ilia@18415
   355
        private final String message;
ilia@18415
   356
ilia@18415
   357
        public FatalErrorInfo(String id, String message) {
ilia@18415
   358
            this.id = id;
ilia@18415
   359
            this.message = message;
ilia@18415
   360
        }
ilia@18415
   361
ilia@18415
   362
        @Override
ilia@18415
   363
        public String getMessage() {
ilia@18415
   364
            return message;
ilia@18415
   365
        }
ilia@18415
   366
ilia@18415
   367
        @Override
ilia@18415
   368
        public Severity getSeverity() {
ilia@18415
   369
            return Severity.WARNING;
ilia@18415
   370
        }
ilia@18415
   371
ilia@18415
   372
        @Override
ilia@18415
   373
        public int getStartOffset() {
ilia@18415
   374
            return 0;
ilia@18415
   375
        }
ilia@18415
   376
ilia@18415
   377
        @Override
ilia@18415
   378
        public int getEndOffset() {
ilia@18415
   379
            return 1;
ilia@18415
   380
        }
ilia@18415
   381
ilia@18415
   382
        @Override
ilia@18415
   383
        public String getId() {
ilia@18415
   384
            return id;
ilia@18415
   385
        }
ilia@18415
   386
    }
ilia@18415
   387
ilia@18415
   388
    @ServiceProvider(service = CsmErrorInfoHintProvider.class, position = 9100)
ilia@18415
   389
    public final static class ModerinzeHintProvider extends CsmErrorInfoHintProvider {
ilia@18415
   390
ilia@18415
   391
        @Override
ilia@18415
   392
        protected List<Fix> doGetFixes(CsmErrorInfo info, List<Fix> alreadyFound) {
ilia@18415
   393
            if (info instanceof ModernizeErrorInfo) {
ilia@18415
   394
                alreadyFound.add(new ConfigureHintsFix((ModernizeErrorInfo) info));
ilia@18415
   395
            }
ilia@18415
   396
            return alreadyFound;
ilia@18415
   397
        }
ilia@18415
   398
    }
ilia@18415
   399
ilia@18415
   400
    @ServiceProvider(service = CsmErrorInfoHintProvider.class, position = 1600)
ilia@18415
   401
    public static final class ModernizeFixProvider extends CsmErrorInfoHintProvider {
ilia@18415
   402
ilia@18415
   403
        @Override
ilia@18415
   404
        protected List<Fix> doGetFixes(CsmErrorInfo info, List<Fix> alreadyFound) {
ilia@18415
   405
            alreadyFound.addAll(createFixes(info));
ilia@18415
   406
            return alreadyFound;
ilia@18415
   407
        }
ilia@18415
   408
    }
ilia@18415
   409
ilia@18415
   410
    private static List<? extends Fix> createFixes(CsmErrorInfo info) {
ilia@18415
   411
        if (info instanceof ModernizeErrorInfo) {
ilia@18415
   412
            ModernizeErrorInfo mei = (ModernizeErrorInfo) info;
ilia@18415
   413
            List<Replacement> replacements = mei.getDiagnostics().getReplacements();
ilia@18415
   414
            if (!replacements.isEmpty()) {
ilia@18415
   415
                return Collections.singletonList(new ModernizeFix(replacements, mei.getId()));
ilia@18415
   416
            }
ilia@18415
   417
        }
ilia@18415
   418
        return Collections.EMPTY_LIST;
ilia@18415
   419
    }
ilia@18415
   420
}