| /* |
| * Copyright (C) 2013 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.tools.idea.gradle.output.parser.javac; |
| |
| import com.android.SdkConstants; |
| 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.ParsingFailedException; |
| import com.android.ide.common.blame.parser.PatternAwareOutputParser; |
| import com.android.ide.common.blame.parser.util.OutputLineReader; |
| import com.android.utils.ILogger; |
| import com.google.common.collect.Lists; |
| import com.intellij.util.StringBuilderSpinAllocator; |
| import com.intellij.util.SystemProperties; |
| import org.jetbrains.annotations.Contract; |
| import org.jetbrains.annotations.NonNls; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| import java.io.File; |
| import java.util.List; |
| |
| /** |
| * Parses javac's output. |
| */ |
| public class JavacOutputParser implements PatternAwareOutputParser { |
| private static final char COLON = ':'; |
| |
| private static final String WARNING_PREFIX = "warning:"; // default value |
| |
| @Override |
| public boolean parse(@NotNull String line, @NotNull OutputLineReader reader, @NotNull List<Message> messages, @NotNull ILogger logger) |
| throws ParsingFailedException { |
| 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(); |
| if (part1.equalsIgnoreCase("error") /* jikes */ || part1.equalsIgnoreCase("Caused by")) { |
| // +1 so we don't include the colon |
| String text = line.substring(colonIndex1 + 1).trim(); |
| addMessage(new Message(Message.Kind.ERROR, text, SourceFilePosition.UNKNOWN), messages); |
| return true; |
| } |
| if (part1.equalsIgnoreCase("warning")) { |
| // +1 so we don't include the colon |
| String text = line.substring(colonIndex1 + 1).trim(); |
| addMessage(new Message(Message.Kind.WARNING, text, SourceFilePosition.UNKNOWN), messages); |
| return true; |
| } |
| if (part1.equalsIgnoreCase("javac")) { |
| addMessage(new Message(Message.Kind.ERROR, line, SourceFilePosition.UNKNOWN), messages); |
| return true; |
| } |
| |
| 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. |
| String text = line.substring(colonIndex2 + 1).trim(); |
| Message.Kind kind = Message.Kind.ERROR; |
| |
| if (text.startsWith(WARNING_PREFIX)) { |
| text = text.substring(WARNING_PREFIX.length()).trim(); |
| kind = Message.Kind.WARNING; |
| } |
| |
| // Only slurp up line pointer (^) information if this is really javac |
| if (!file.getPath().endsWith(SdkConstants.DOT_JAVA)) { |
| // Fall back to the MergingExceptionParser (which handles similar messages in a more general way) |
| return false; |
| } |
| |
| List<String> messageList = Lists.newArrayList(); |
| messageList.add(text); |
| int column; // 0-based. |
| String prevLine = null; |
| do { |
| String nextLine = reader.readLine(); |
| if (nextLine == null) { |
| return false; |
| } |
| if (nextLine.trim().equals("^")) { |
| column = nextLine.indexOf('^'); |
| 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 = StringBuilderSpinAllocator.alloc(); |
| try { |
| for (String m : messageList) { |
| if (buf.length() > 0) { |
| buf.append(SystemProperties.getLineSeparator()) ; |
| } |
| buf.append(m); |
| } |
| Message msg = new Message(kind, buf.toString(), new SourceFilePosition(file, new SourcePosition(lineNumber - 1, column, -1))); |
| addMessage(msg, messages); |
| } finally { |
| StringBuilderSpinAllocator.dispose(buf); |
| } |
| return true; |
| } |
| |
| } catch (NumberFormatException ignored) { |
| } |
| } |
| } |
| |
| if (line.endsWith("java.lang.OutOfMemoryError")) { |
| addMessage(new Message(Message.Kind.ERROR, "Out of memory.", SourceFilePosition.UNKNOWN), messages); |
| return true; |
| } |
| |
| return false; |
| } |
| |
| private static void addMessage(@NotNull Message message, @NotNull 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); |
| } |
| } |
| |
| @Contract("null -> false") |
| private static boolean isMessageEnd(@Nullable String line) { |
| return line != null && line.length() > 0 && Character.isWhitespace(line.charAt(0)); |
| } |
| |
| @NotNull |
| private static List<String> convertMessages(@NotNull 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){ |
| @NonNls 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; |
| } |
| } |