ide.analysis.modernize/src/org/netbeans/modules/ide/analysis/modernize/impl/YamlParser.java
1.1 --- a/ide.analysis.modernize/src/org/netbeans/modules/ide/analysis/modernize/impl/YamlParser.java Wed Jun 07 18:50:35 2017 +0300
1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
1.3 @@ -1,357 +0,0 @@
1.4 -/*
1.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
1.6 - *
1.7 - * Copyright (c) 2017 Oracle and/or its affiliates. All rights reserved.
1.8 - *
1.9 - * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
1.10 - * Other names may be trademarks of their respective owners.
1.11 - *
1.12 - * The contents of this file are subject to the terms of either the GNU
1.13 - * General Public License Version 2 only ("GPL") or the Common
1.14 - * Development and Distribution License("CDDL") (collectively, the
1.15 - * "License"). You may not use this file except in compliance with the
1.16 - * License. You can obtain a copy of the License at
1.17 - * http://www.netbeans.org/cddl-gplv2.html
1.18 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
1.19 - * specific language governing permissions and limitations under the
1.20 - * License. When distributing the software, include this License Header
1.21 - * Notice in each file and include the License file at
1.22 - * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
1.23 - * particular file as subject to the "Classpath" exception as provided
1.24 - * by Oracle in the GPL Version 2 section of the License file that
1.25 - * accompanied this code. If applicable, add the following below the
1.26 - * License Header, with the fields enclosed by brackets [] replaced by
1.27 - * your own identifying information:
1.28 - * "Portions Copyrighted [year] [name of copyright owner]"
1.29 - *
1.30 - * If you wish your version of this file to be governed by only the CDDL
1.31 - * or only the GPL Version 2, indicate your decision by adding
1.32 - * "[Contributor] elects to include this software in this distribution
1.33 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
1.34 - * single choice of license, a recipient has the option to distribute
1.35 - * your version of this file under either the CDDL, the GPL Version 2 or
1.36 - * to extend the choice of license to its licensees as provided above.
1.37 - * However, if you add GPL Version 2 code and therefore, elected the GPL
1.38 - * Version 2 license, then the option applies only if the new code is
1.39 - * made subject to such option by the copyright holder.
1.40 - *
1.41 - * Contributor(s): Ilia Gromov
1.42 - */
1.43 -package org.netbeans.modules.ide.analysis.modernize.impl;
1.44 -
1.45 -import static org.netbeans.modules.ide.analysis.modernize.impl.YamlParser.Diagnostics.UNDEFINED;
1.46 -import java.util.ArrayList;
1.47 -import java.util.Collections;
1.48 -import java.util.List;
1.49 -import java.util.StringTokenizer;
1.50 -import java.util.logging.Level;
1.51 -
1.52 -/**
1.53 - *
1.54 - * @author Ilia Gromov
1.55 - */
1.56 -public class YamlParser {
1.57 - // TODO check for no-replacements case
1.58 -
1.59 - private static final YamlParser INSTANCE = new YamlParser();
1.60 -
1.61 - public static YamlParser getDefault() {
1.62 - return INSTANCE;
1.63 - }
1.64 -
1.65 - private static final String OPEN_TAG = "---"; //NOI18N
1.66 - private static final String CLOSE_TAG = "..."; //NOI18N
1.67 -
1.68 - private static final String MAIN_SOURCE_FILE = "MainSourceFile"; //NOI18N
1.69 - private static final String CHECK_NAME = "CheckName"; //NOI18N
1.70 - private static final String LEVEL = "Level"; //NOI18N
1.71 - private static final String MESSAGE_FILE_PATH = "MessageFilePath"; //NOI18N
1.72 - private static final String MESSAGE_FILE_OFFSET = "MessageFileOffset"; //NOI18N
1.73 - private static final String MESSAGE = "Message"; //NOI18N
1.74 - private static final String REPLACEMENTS = "Replacements"; //NOI18N
1.75 - private static final String DIAGNOSTICS = "Diagnostics"; //NOI18N
1.76 -
1.77 - private static final String FILE_PATH = "FilePath"; //NOI18N
1.78 - private static final String OFFSET = "Offset"; //NOI18N
1.79 - private static final String LENGTH = "Length"; //NOI18N
1.80 - private static final String REPLACEMENT_TEXT = "ReplacementText"; //NOI18N
1.81 -
1.82 - // clang-modernize:
1.83 -// ---
1.84 -// MainSourceFile: /home/ilia/NetBeansProjects/CppApplication_46/main.cpp
1.85 -// Replacements:
1.86 -// - FilePath: /home/ilia/NetBeansProjects/CppApplication_46/newfile.h
1.87 -// Offset: 101
1.88 -// Length: 1
1.89 -// ReplacementText: nullptr
1.90 -// - FilePath: /home/ilia/NetBeansProjects/CppApplication_46/newfile1.h
1.91 -// Offset: 380
1.92 -// Length: 1
1.93 -// ReplacementText: nullptr
1.94 -// - FilePath: /home/ilia/NetBeansProjects/CppApplication_46/main.cpp
1.95 -// Offset: 152
1.96 -// Length: 1
1.97 -// ReplacementText: nullptr
1.98 -// ...
1.99 - // clang-tidy:
1.100 -// ---
1.101 -// MainSourceFile: ''
1.102 -// Diagnostics:
1.103 -// CheckName: misc-macro-parentheses
1.104 -// Replacements:
1.105 -// - FilePath: /media/SSD_/code/zdoom/main_1.cpp
1.106 -// Offset: 1352
1.107 -// Length: 0
1.108 -// ReplacementText: '('
1.109 -// - FilePath: /media/SSD_/code/zdoom/main_1.cpp
1.110 -// Offset: 1353
1.111 -// Length: 0
1.112 -// ReplacementText: ')'
1.113 -// Diagnostics:
1.114 -// CheckName: misc-macro-parentheses
1.115 -// Replacements:
1.116 -// - FilePath: /media/SSD_/code/zdoom/main_1.cpp
1.117 -// Offset: 1446
1.118 -// Length: 0
1.119 -// ReplacementText: '('
1.120 -// - FilePath: /media/SSD_/code/zdoom/main_1.cpp
1.121 -// Offset: 1447
1.122 -// Length: 0
1.123 -// ReplacementText: ')'
1.124 -// ...
1.125 - public List<Diagnostics> parseYaml(String output) {
1.126 - try {
1.127 - if (output.isEmpty()) {
1.128 - // No warnings in header = no 'Main Source File' element
1.129 - return Collections.EMPTY_LIST;
1.130 - }
1.131 - StringTokenizer st = new StringTokenizer(output, "\n"); //NOI18N
1.132 - String line;
1.133 -
1.134 - // ---
1.135 - line = st.nextToken();
1.136 -
1.137 - line = st.nextToken();
1.138 - String mainSourceFile = getValue(MAIN_SOURCE_FILE, line);
1.139 -
1.140 - // Replacements:
1.141 - line = st.nextToken();
1.142 - ClangTidyVersion version = line.contains(REPLACEMENTS)
1.143 - ? ClangTidyVersion.OLD_FORMAT
1.144 - : ClangTidyVersion.NEW_FORMAT;
1.145 -
1.146 - List<Diagnostics> list = version.parser.parse(st);
1.147 -
1.148 - return list;
1.149 - } catch (Exception ex) {
1.150 - ModernizeErrorProvider.LOG.log(Level.INFO, "Can't parse output line");
1.151 - return Collections.EMPTY_LIST;
1.152 - }
1.153 - }
1.154 -
1.155 - private static List<Replacement> parseReplacements(StringTokenizer st) {
1.156 - List<Replacement> replacements = new ArrayList<Replacement>();
1.157 - String line;
1.158 -
1.159 - // eat Replacements:
1.160 - line = st.nextToken();
1.161 -
1.162 - if (!line.contains(REPLACEMENTS)) {
1.163 - return replacements;
1.164 - }
1.165 -
1.166 - while (st.hasMoreTokens()) {
1.167 - line = st.nextToken();
1.168 -
1.169 - if (line.equals(CLOSE_TAG) || !line.contains(FILE_PATH)) {
1.170 - break;
1.171 - }
1.172 -
1.173 - String filePath = getValue(FILE_PATH, line);
1.174 -
1.175 - line = st.nextToken();
1.176 - int offset = Integer.parseInt(getValue(OFFSET, line));
1.177 -
1.178 - line = st.nextToken();
1.179 - int length = Integer.parseInt(getValue(LENGTH, line));
1.180 -
1.181 - line = st.nextToken();
1.182 - String replacementText = getValue(REPLACEMENT_TEXT, line);
1.183 - while (replacementText == null && st.hasMoreElements()) {
1.184 - line = line + "\n" + st.nextElement(); //NOI18N
1.185 - replacementText = getValue(REPLACEMENT_TEXT, line);
1.186 - }
1.187 -
1.188 - Replacement replacement = new Replacement(filePath, offset, length, replacementText);
1.189 - replacements.add(replacement);
1.190 -
1.191 - }
1.192 - return replacements;
1.193 - }
1.194 -
1.195 - private static String getValue(String key, String line) {
1.196 - int keyStart = line.indexOf(key);
1.197 - assert keyStart != -1;
1.198 - int keyEnd = keyStart + key.length() + 1;
1.199 - String trimmed = line.substring(keyEnd).trim();
1.200 - boolean isTextValue = trimmed.charAt(0) == '\'';
1.201 - if (isTextValue) {
1.202 - if (trimmed.length() == 1) {
1.203 - // '
1.204 - // abcd'
1.205 - return null;
1.206 - } else if (trimmed.charAt(trimmed.length() - 1) == '\'') {
1.207 - trimmed = trimmed.substring(1, trimmed.length() - 1);
1.208 - } else {
1.209 - return null;
1.210 - }
1.211 - }
1.212 - return trimmed;
1.213 - }
1.214 -
1.215 - public static class TranslationUnitDiagnostics {
1.216 -
1.217 - private final String mainSourceFilePath;
1.218 - private final String context;
1.219 - private final List<Diagnostics> diags;
1.220 -
1.221 - public TranslationUnitDiagnostics(String mainSourceFilePath, String context, List<Diagnostics> diags) {
1.222 - this.mainSourceFilePath = mainSourceFilePath;
1.223 - this.context = context;
1.224 - this.diags = diags;
1.225 - }
1.226 -
1.227 - public String getMainSourceFilePath() {
1.228 - return mainSourceFilePath;
1.229 - }
1.230 -
1.231 - public String getContext() {
1.232 - return context;
1.233 - }
1.234 -
1.235 - public List<Diagnostics> getDiags() {
1.236 - return diags;
1.237 - }
1.238 - }
1.239 -
1.240 - public static class Diagnostics {
1.241 -
1.242 - public static final String UNDEFINED = "undefined"; // NOI18N
1.243 -
1.244 - public enum Level {
1.245 - warning, error
1.246 - }
1.247 -
1.248 - private final String checkName;
1.249 - private final Diagnostics.Level level;
1.250 - private final String messageFilePath;
1.251 - private final int messageFileOffset;
1.252 - private final String message;
1.253 - private final List<Replacement> replacements;
1.254 -
1.255 - public Diagnostics(String checkName, Diagnostics.Level level, String messageFilePath, int messageFileOffset, String message, List<Replacement> replacements) {
1.256 - this.checkName = checkName;
1.257 - this.level = level;
1.258 - this.messageFilePath = messageFilePath;
1.259 - this.messageFileOffset = messageFileOffset;
1.260 - this.message = message;
1.261 - this.replacements = replacements;
1.262 - }
1.263 -
1.264 - public String getCheckName() {
1.265 - return checkName;
1.266 - }
1.267 -
1.268 - public Level getLevel() {
1.269 - return level;
1.270 - }
1.271 -
1.272 - public String getMessageFilePath() {
1.273 - return messageFilePath;
1.274 - }
1.275 -
1.276 - public int getMessageFileOffset() {
1.277 - return messageFileOffset;
1.278 - }
1.279 -
1.280 - public String getMessage() {
1.281 - return message;
1.282 - }
1.283 -
1.284 - public List<Replacement> getReplacements() {
1.285 - return replacements;
1.286 - }
1.287 - }
1.288 -
1.289 - public static class Replacement {
1.290 -
1.291 - public final String filePath;
1.292 - public final int offset;
1.293 - public final int length;
1.294 - public final String replacementText;
1.295 -
1.296 - public Replacement(String FilePath, int offset, int length, String replacementText) {
1.297 - this.filePath = FilePath;
1.298 - this.offset = offset;
1.299 - this.length = length;
1.300 - this.replacementText = replacementText;
1.301 - }
1.302 - }
1.303 -
1.304 - private static enum ClangTidyVersion {
1.305 - NEW_FORMAT(new NewFormatParser()),
1.306 - OLD_FORMAT(new OldFormatParser());
1.307 -
1.308 - public final TidyParser parser;
1.309 -
1.310 - private ClangTidyVersion(TidyParser parser) {
1.311 - this.parser = parser;
1.312 - }
1.313 - }
1.314 -
1.315 - private static abstract class TidyParser {
1.316 -
1.317 - abstract List<Diagnostics> parse(StringTokenizer st);
1.318 - }
1.319 -
1.320 - private static class NewFormatParser extends TidyParser {
1.321 -
1.322 - @Override
1.323 - public List<Diagnostics> parse(StringTokenizer st) {
1.324 - List<Diagnostics> list = new ArrayList<Diagnostics>();
1.325 -
1.326 - String line;
1.327 - while (st.hasMoreElements()) {
1.328 - line = st.nextToken();
1.329 - String checkName = getValue(CHECK_NAME, line);
1.330 -
1.331 - line = st.nextToken();
1.332 - Diagnostics.Level level = Diagnostics.Level.valueOf(getValue(LEVEL, line).toLowerCase());
1.333 -
1.334 - line = st.nextToken();
1.335 - String messageFilePath = getValue(MESSAGE_FILE_PATH, line);
1.336 -
1.337 - line = st.nextToken();
1.338 - int messageFileOffset = Integer.parseInt(getValue(MESSAGE_FILE_OFFSET, line));
1.339 -
1.340 - line = st.nextToken();
1.341 - String message = getValue(MESSAGE, line);
1.342 -
1.343 - List<Replacement> replacements = parseReplacements(st);
1.344 -
1.345 - list.add(new Diagnostics(checkName, level, messageFilePath, messageFileOffset, message, replacements));
1.346 - }
1.347 - return list;
1.348 - }
1.349 -
1.350 - }
1.351 -
1.352 - private static class OldFormatParser extends TidyParser {
1.353 -
1.354 - @Override
1.355 - public List<Diagnostics> parse(StringTokenizer st) {
1.356 - List<Replacement> parseReplacements = parseReplacements(st);
1.357 - return Collections.singletonList(new Diagnostics(UNDEFINED, Diagnostics.Level.warning, "", -1, "", parseReplacements)); //NOI18N
1.358 - }
1.359 - }
1.360 -}