/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.ide.common.blame.parser; import com.android.annotations.NonNull; import com.android.annotations.Nullable; import com.android.ide.common.blame.Message; import com.android.ide.common.blame.SourceFilePosition; import com.android.ide.common.blame.SourcePosition; import com.android.ide.common.blame.parser.util.OutputLineReader; import com.android.utils.ILogger; import com.android.utils.SdkUtils; import com.google.common.base.Splitter; import com.google.common.collect.Lists; import java.io.File; import java.util.List; import java.util.Locale; /** * Parses output from the legacy NDK support. */ public class LegacyNdkOutputParser implements PatternAwareOutputParser { private static final String FROM = "from"; private static final String UNKNOWN_MSG_PREFIX1 = "In file included " + FROM; private static final String UNKNOWN_MSG_PREFIX2 = " " + FROM; private static final char COLON = ':'; @Override public boolean parse(@NonNull String line, @NonNull OutputLineReader reader, @NonNull List<Message> messages, @NonNull ILogger logger) throws ParsingFailedException { // Parses unknown message if (line.startsWith(UNKNOWN_MSG_PREFIX1) || line.startsWith(UNKNOWN_MSG_PREFIX2)) { int fromIndex = line.indexOf(FROM); String unknownMsgCause = line.substring(0, fromIndex).trim(); unknownMsgCause = "(Unknown) " + unknownMsgCause; String coordinates = line.substring(fromIndex + FROM.length()).trim(); if (!coordinates.isEmpty()) { int colonIndex1 = line.indexOf(COLON); if (colonIndex1 == 1) { // drive letter (Windows) coordinates = coordinates.substring(colonIndex1 + 1); } if (coordinates.endsWith(",") || coordinates.endsWith(":")) { coordinates = coordinates.substring(0, coordinates.length() - 1); } List<String> segments = Splitter.on(COLON).splitToList(coordinates); if (segments.size() == 3) { String pathname = segments.get(0); File file = new File(pathname); int lineNumber = 0; try { lineNumber = Integer.parseInt(segments.get(1)); } catch (NumberFormatException ignore) { } int column = 0; try { column = Integer.parseInt(segments.get(2)); } catch (NumberFormatException ignore) { } SourceFilePosition position = new SourceFilePosition(file, new SourcePosition(lineNumber - 1, column - 1, -1)); Message message = new Message(Message.Kind.INFO, unknownMsgCause.trim(), position); if (!messages.contains(message)) { // There may be a few duplicate "unknown" messages addMessage(message, messages); } } } return true; } // Parses unresolved include. int colonIndex1 = line.indexOf(COLON); if (colonIndex1 == 1) { // drive letter (Windows) colonIndex1 = line.indexOf(COLON, colonIndex1 + 1); } if (colonIndex1 >= 0) { // looks like found something like a file path. String part1 = line.substring(0, colonIndex1).trim(); int colonIndex2 = line.indexOf(COLON, colonIndex1 + 1); if (colonIndex2 >= 0) { File file = new File(part1); if (!file.isFile()) { // the part one is not a file path. return false; } try { int lineNumber = Integer.parseInt( line.substring(colonIndex1 + 1, colonIndex2).trim()); // 1-based. int colonIndex3 = line.indexOf(COLON, colonIndex2 + 1); if (colonIndex1 >= 0) { int column = Integer.parseInt( line.substring(colonIndex2 + 1, colonIndex3).trim()); int colonIndex4 = line.indexOf(COLON, colonIndex3 + 1); if (colonIndex4 >= 0) { Message.Kind kind = Message.Kind.INFO; String severity = line.substring(colonIndex3 + 1, colonIndex4).toLowerCase(Locale.getDefault()).trim(); if (severity.endsWith("error")) { kind = Message.Kind.ERROR; } else if (severity.endsWith("warning")) { kind = Message.Kind.WARNING; } String text = line.substring(colonIndex4 + 1).trim(); List<String> messageList = Lists.newArrayList(); messageList.add(text); String prevLine = null; do { String nextLine = reader.readLine(); if (nextLine == null) { return false; } if (nextLine.trim().equals("^")) { String messageEnd = reader.readLine(); while (isMessageEnd(messageEnd)) { messageList.add(messageEnd.trim()); messageEnd = reader.readLine(); } if (messageEnd != null) { reader.pushBack(messageEnd); } break; } if (prevLine != null) { messageList.add(prevLine); } prevLine = nextLine; } while (true); if (column >= 0) { messageList = convertMessages(messageList); StringBuilder buf = new StringBuilder(); for (String m : messageList) { if (buf.length() > 0) { buf.append(SdkUtils.getLineSeparator()); } buf.append(m); } Message msg = new Message(kind, buf.toString(), new SourceFilePosition(file, new SourcePosition(lineNumber - 1, column - 1, -1))); if (!messages.contains(msg)) { addMessage(msg, messages); } return true; } } } } catch (NumberFormatException ignored) { } } } return false; } private static void addMessage(@NonNull Message message, @NonNull List<Message> messages) { boolean duplicatesPrevious = false; int messageCount = messages.size(); if (messageCount > 0) { Message lastMessage = messages.get(messageCount - 1); duplicatesPrevious = lastMessage.equals(message); } if (!duplicatesPrevious) { messages.add(message); } } private static boolean isMessageEnd(@Nullable String line) { return line != null && !line.isEmpty() && Character.isWhitespace(line.charAt(0)); } @NonNull private static List<String> convertMessages(@NonNull List<String> messages) { if (messages.size() <= 1) { return messages; } final String line0 = messages.get(0); final String line1 = messages.get(1); final int colonIndex = line1.indexOf(':'); if (colonIndex > 0) { String part1 = line1.substring(0, colonIndex).trim(); // jikes if ("symbol".equals(part1)) { String symbol = line1.substring(colonIndex + 1).trim(); messages.remove(1); if (messages.size() >= 2) { messages.remove(1); } messages.set(0, line0 + " " + symbol); } } return messages; } }