Search in sources :

Example 11 with SourceFilePosition

use of com.android.ide.common.blame.SourceFilePosition in project android by JetBrains.

the class MergingExceptionParser method parse.

@Override
public boolean parse(@NotNull String line, @NotNull OutputLineReader reader, @NotNull List<Message> messages, @NotNull ILogger logger) throws ParsingFailedException {
    boolean hasError = false;
    int messageIndex;
    Message.Kind kind = null;
    //noinspection SpellCheckingInspection
    if (line.contains("rror: ")) {
        messageIndex = line.indexOf(": Error: ");
        if (messageIndex == -1) {
            messageIndex = line.indexOf(": error: ");
            if (messageIndex == -1) {
                return false;
            }
        }
        kind = Message.Kind.ERROR;
    } else {
        //noinspection SpellCheckingInspection
        if (line.contains("arning: ")) {
            messageIndex = line.indexOf(": Warning: ");
            if (messageIndex == -1) {
                messageIndex = line.indexOf(": warning: ");
                if (messageIndex == -1) {
                    return false;
                }
            }
            kind = Message.Kind.WARNING;
        } else {
            return false;
        }
    }
    // TODO: This doesn't handle ambiguous scenarios where the error message itself contains ": " or the path contains " : ".
    // I could disambiguate this by checking file existence on the path component containing a ":" !
    // See if it's preceded by a line number and/or a column
    String path;
    int lineNumber = -1;
    int column = -1;
    int colon = line.lastIndexOf(':', messageIndex - 1);
    if (colon != -1) {
        // Is there a column?
        int colon2 = line.lastIndexOf(':', colon - 1);
        if (colon2 != -1) {
            // Both line number and column
            //lineNumber =
            String columnString = line.substring(colon + 1, messageIndex);
            String lineString = line.substring(colon2 + 1, colon);
            try {
                column = Integer.parseInt(columnString);
                lineNumber = Integer.parseInt(lineString);
            } catch (NumberFormatException e) {
                // Could it be a Windows path with drive letters (and no line number) ?
                if (colon2 == 1) {
                    String p = line.substring(0, colon);
                    if (new File(p).exists()) {
                        colon2 = colon;
                    } else {
                        return false;
                    }
                } else {
                    return false;
                }
            }
            path = line.substring(0, colon2);
        } else {
            // Just one number: it's the line
            try {
                lineNumber = Integer.parseInt(line.substring(colon + 1, messageIndex));
            } catch (NumberFormatException e) {
                // Could it be a Windows path with drive letters (and no line number) ?
                if (colon == 1) {
                    String p = line.substring(0, messageIndex);
                    if (new File(p).exists()) {
                        colon = messageIndex;
                    } else {
                        return false;
                    }
                } else {
                    return false;
                }
            }
            path = line.substring(0, colon);
        }
    } else {
        path = line.substring(0, messageIndex);
    }
    String message = line.substring(messageIndex + 2);
    messages.add(new Message(kind, message, new SourceFilePosition(new File(path), new SourcePosition(lineNumber - 1, column - 1, -1))));
    return true;
}
Also used : SourceFilePosition(com.android.ide.common.blame.SourceFilePosition) Message(com.android.ide.common.blame.Message) SourcePosition(com.android.ide.common.blame.SourcePosition) File(java.io.File)

Example 12 with SourceFilePosition

use of com.android.ide.common.blame.SourceFilePosition in project android by JetBrains.

the class XmlValidationErrorParser method parse.

@Override
public boolean parse(@NotNull String line, @NotNull OutputLineReader reader, @NotNull List<Message> messages, @NotNull ILogger logger) throws ParsingFailedException {
    Matcher m1 = FATAL_ERROR.matcher(line);
    if (!m1.matches()) {
        // Sometimes the parse failure message appears by itself (for example with duplicate resources);
        // in this case also recognize the line by itself even though it's separated from the next message
        Matcher m2 = FILE_REFERENCE.matcher(line);
        if (m2.matches()) {
            File sourceFile = new File(m2.group(1));
            if (sourceFile.exists()) {
                String message = line;
                // Eat the entire stacktrace
                String exceptionMessage = ParserUtil.digestStackTrace(reader);
                if (exceptionMessage != null) {
                    message = exceptionMessage + ": " + message;
                }
                messages.add(new Message(Message.Kind.ERROR, message, new SourceFilePosition(sourceFile, SourcePosition.UNKNOWN)));
                return true;
            }
        }
        return false;
    }
    String message = m1.group(3);
    int lineNumber = Integer.parseInt(m1.group(1));
    int column = Integer.parseInt(m1.group(2));
    SourceFile sourceFile = SourceFile.UNKNOWN;
    String nextLine = reader.peek(0);
    if (nextLine == null) {
        return false;
    }
    Matcher m2 = FILE_REFERENCE.matcher(nextLine);
    if (m2.matches()) {
        // digest peeked line
        reader.readLine();
        File possibleSourceFile = new File(m2.group(1));
        if (possibleSourceFile.exists()) {
            sourceFile = new SourceFile(possibleSourceFile);
        }
    }
    messages.add(new Message(Message.Kind.ERROR, message, new SourceFilePosition(sourceFile, new SourcePosition(lineNumber - 1, column - 1, -1))));
    return true;
}
Also used : SourceFilePosition(com.android.ide.common.blame.SourceFilePosition) Message(com.android.ide.common.blame.Message) Matcher(java.util.regex.Matcher) SourcePosition(com.android.ide.common.blame.SourcePosition) SourceFile(com.android.ide.common.blame.SourceFile) SourceFile(com.android.ide.common.blame.SourceFile) File(java.io.File)

Example 13 with SourceFilePosition

use of com.android.ide.common.blame.SourceFilePosition in project android by JetBrains.

the class JavacOutputParser method parse.

@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 {
                // 1-based.
                int lineNumber = Integer.parseInt(line.substring(colonIndex1 + 1, colonIndex2).trim());
                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);
                // 0-based.
                int column;
                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();
                        }
                        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;
}
Also used : SourceFilePosition(com.android.ide.common.blame.SourceFilePosition) Message(com.android.ide.common.blame.Message) SourcePosition(com.android.ide.common.blame.SourcePosition) File(java.io.File)

Example 14 with SourceFilePosition

use of com.android.ide.common.blame.SourceFilePosition in project android by JetBrains.

the class BuildFailureParser method parse.

@Override
public boolean parse(@NotNull String line, @NotNull OutputLineReader reader, @NotNull List<Message> messages, @NotNull ILogger logger) throws ParsingFailedException {
    State state = State.BEGINNING;
    int pos = 0;
    String currentLine = line;
    SourceFile file = SourceFile.UNKNOWN;
    SourcePosition position = SourcePosition.UNKNOWN;
    String lastQuotedLine = null;
    StringBuilder errorMessage = new StringBuilder();
    Matcher matcher;
    // some of the output. We should fall back to emitting all the output in that case.
    while (true) {
        switch(state) {
            case BEGINNING:
                if (WHERE_LINE_1.matcher(currentLine).matches()) {
                    state = State.WHERE;
                } else if (!BEGINNING_PATTERNS[pos].matcher(currentLine).matches()) {
                    return false;
                } else if (++pos >= BEGINNING_PATTERNS.length) {
                    state = State.MESSAGE;
                }
                break;
            case WHERE:
                matcher = WHERE_LINE_2.matcher(currentLine);
                if (!matcher.matches()) {
                    return false;
                }
                file = new SourceFile(new File(matcher.group(1)));
                position = new SourcePosition(Integer.parseInt(matcher.group(2)) - 1, 0, -1);
                state = State.BEGINNING;
                break;
            case MESSAGE:
                if (ENDING_PATTERNS[0].matcher(currentLine).matches()) {
                    state = State.ENDING;
                    pos = 1;
                } else if (COMMAND_FAILURE_MESSAGE.matcher(currentLine).matches()) {
                    state = State.COMMAND_FAILURE_COMMAND_LINE;
                } else if (COMPILE_FAILURE_MESSAGE.matcher(currentLine).matches()) {
                    state = State.COMPILE_FAILURE_OUTPUT;
                    // We don't need errorMessage anymore.
                    // Individual errors will be reported.
                    errorMessage.setLength(0);
                } else {
                    // Determine whether the string starts with ">" (possibly indented by whitespace), and if so, where
                    int quoted = -1;
                    for (int i = 0, n = currentLine.length(); i < n; i++) {
                        char c = currentLine.charAt(i);
                        if (c == '>') {
                            quoted = i;
                            break;
                        } else if (!Character.isWhitespace(c)) {
                            break;
                        }
                    }
                    if (quoted != -1) {
                        if (currentLine.startsWith("> In DataSet ", quoted) && currentLine.contains("no data file for changedFile")) {
                            matcher = Pattern.compile("\\s*> In DataSet '.+', no data file for changedFile '(.+)'").matcher(currentLine);
                            if (matcher.find()) {
                                file = new SourceFile(new File(matcher.group(1)));
                            }
                        } else if (currentLine.startsWith("> Duplicate resources: ", quoted)) {
                            // For exact format, see com.android.ide.common.res2.DuplicateDataException
                            matcher = Pattern.compile("\\s*> Duplicate resources: (.+):(.+), (.+):(.+)\\s*").matcher(currentLine);
                            if (matcher.matches()) {
                                file = new SourceFile(new File(matcher.group(1)));
                                position = AbstractAaptOutputParser.findResourceLine(file.getSourceFile(), matcher.group(2), logger);
                                File other = new File(matcher.group(3));
                                SourcePosition otherPos = AbstractAaptOutputParser.findResourceLine(other, matcher.group(4), logger);
                                messages.add(new Message(Message.Kind.ERROR, currentLine, new SourceFilePosition(file, position), new SourceFilePosition(other, otherPos)));
                                // Skip appending to the errorMessage buffer; we've already added both locations to the message
                                break;
                            }
                        } else if (currentLine.startsWith("> Problems pinging owner of lock ", quoted)) {
                            String text = "Possibly unstable network connection: Failed to connect to lock owner. Try to rebuild.";
                            messages.add(new Message(Message.Kind.ERROR, text, SourceFilePosition.UNKNOWN));
                        }
                    }
                    boolean handledByDataBinding = myDataBindingParser.parse(currentLine, reader, messages, logger);
                    if (!handledByDataBinding) {
                        if (errorMessage.length() > 0) {
                            errorMessage.append("\n");
                        }
                        errorMessage.append(currentLine);
                    }
                    if (isGradleQuotedLine(currentLine)) {
                        lastQuotedLine = currentLine;
                    }
                }
                break;
            case COMMAND_FAILURE_COMMAND_LINE:
                // Gradle can put an unescaped "Android Studio" in its command-line output. (It doesn't care because this doesn't have to be
                // a perfectly valid command line; it's just an error message). To keep it from messing up our parsing, let's convert those
                // to "Android_Studio". If there are other spaces in the command-line path, though, it will mess up our parsing. Oh, well.
                currentLine = currentLine.replaceAll("Android Studio", "Android_Studio");
                matcher = COMMAND_LINE_PARSER.matcher(currentLine);
                if (matcher.matches()) {
                    String message = String.format("Error while executing %s command", matcher.group(2));
                    messages.add(new Message(Message.Kind.ERROR, message, SourceFilePosition.UNKNOWN));
                } else if (COMMAND_LINE_ERROR_OUTPUT.matcher(currentLine).matches()) {
                    state = State.COMMAND_FAILURE_OUTPUT;
                } else if (ENDING_PATTERNS[0].matcher(currentLine).matches()) {
                    state = State.ENDING;
                    pos = 1;
                }
                break;
            case COMMAND_FAILURE_OUTPUT:
                if (ENDING_PATTERNS[0].matcher(currentLine).matches()) {
                    state = State.ENDING;
                    pos = 1;
                } else {
                    currentLine = currentLine.trim();
                    if (!myAaptParser.parse(currentLine, reader, messages, logger)) {
                        // The AAPT parser punted on it. Just create a message with the unparsed error.
                        messages.add(new Message(Message.Kind.ERROR, currentLine, SourceFilePosition.UNKNOWN));
                    }
                }
                break;
            case COMPILE_FAILURE_OUTPUT:
                if (ENDING_PATTERNS[0].matcher(currentLine).matches()) {
                    state = State.ENDING;
                    pos = 1;
                } else {
                    matcher = COMPILE_LINE_PARSER.matcher(currentLine);
                    if (matcher.matches()) {
                        file = new SourceFile(new File(matcher.group(1)));
                        position = new SourcePosition(Integer.parseInt(matcher.group(2)) - 1, Integer.parseInt(matcher.group(3)) - 1, 0);
                        String text = matcher.group(4);
                        String type = matcher.group(5);
                        Message.Kind kind = Message.Kind.UNKNOWN;
                        if (type.endsWith("error")) {
                            kind = Message.Kind.ERROR;
                        } else if (type.equals("warning")) {
                            kind = Message.Kind.WARNING;
                        } else if (type.equals("note")) {
                            kind = Message.Kind.INFO;
                        }
                        messages.add(new Message(kind, text, new SourceFilePosition(file, position)));
                    }
                }
                break;
            case ENDING:
                if (!ENDING_PATTERNS[pos].matcher(currentLine).matches()) {
                    return false;
                } else if (++pos >= ENDING_PATTERNS.length) {
                    if (errorMessage.length() > 0) {
                        String text = errorMessage.toString();
                        // duplicate resources.
                        if (SourceFile.UNKNOWN.equals(file) && lastQuotedLine != null) {
                            String msg = unquoteGradleLine(lastQuotedLine);
                            Message rootCause = findRootCause(msg, messages);
                            if (rootCause == null) {
                                // Try searching there instead.
                                if (msg.endsWith("Failed to run command:")) {
                                    String[] lines = text.split("\n");
                                    if (lines.length > 2 && lines[lines.length - 2].contains("Output:")) {
                                        String lastLine = lines[lines.length - 1];
                                        if (!lastLine.isEmpty()) {
                                            rootCause = findRootCause(lastLine.trim(), messages);
                                        }
                                    }
                                }
                            }
                            if (rootCause != null) {
                                if (!rootCause.getSourceFilePositions().isEmpty()) {
                                    SourceFilePosition sourceFilePosition = rootCause.getSourceFilePositions().get(0);
                                    file = sourceFilePosition.getFile();
                                    position = sourceFilePosition.getPosition();
                                }
                            }
                        }
                        if (!SourceFile.UNKNOWN.equals(file)) {
                            messages.add(new Message(Message.Kind.ERROR, text, new SourceFilePosition(file, position)));
                        } else if (text.contains("Build cancelled")) {
                            // Gradle throws an exception (BuildCancelledException) when we cancel task processing
                            // (org.gradle.tooling.CancellationTokenSource.cancel()). We don't want to report that as an error though.
                            messages.add(new Message(Message.Kind.INFO, text, SourceFilePosition.UNKNOWN));
                        } else {
                            messages.add(new Message(Message.Kind.ERROR, text, SourceFilePosition.UNKNOWN));
                        }
                    }
                    return true;
                }
                break;
        }
        while (true) {
            currentLine = reader.readLine();
            if (currentLine == null) {
                return false;
            }
            if (!currentLine.trim().isEmpty()) {
                break;
            }
        }
    }
}
Also used : Message(com.android.ide.common.blame.Message) Matcher(java.util.regex.Matcher) SourceFilePosition(com.android.ide.common.blame.SourceFilePosition) SourcePosition(com.android.ide.common.blame.SourcePosition) SourceFile(com.android.ide.common.blame.SourceFile) SourceFile(com.android.ide.common.blame.SourceFile) File(java.io.File)

Example 15 with SourceFilePosition

use of com.android.ide.common.blame.SourceFilePosition in project android by JetBrains.

the class DataBindingOutputParser method parseErrorIn.

private static boolean parseErrorIn(@NotNull String output, @NotNull List<Message> messages) {
    String message;
    String file = "";
    List<Location> locations = new ArrayList<Location>();
    int msgStart = output.indexOf(MSG_KEY);
    if (msgStart < 0) {
        message = output;
    } else {
        int fileStart = output.indexOf(FILE_KEY, msgStart + MSG_KEY.length());
        if (fileStart < 0) {
            message = output;
        } else {
            message = output.substring(msgStart + MSG_KEY.length(), fileStart);
            int locStart = output.indexOf(LOCATION_KEY, fileStart + FILE_KEY.length());
            if (locStart < 0) {
                file = output.substring(fileStart + FILE_KEY.length()).trim();
            } else {
                file = output.substring(fileStart + FILE_KEY.length(), locStart).trim();
                int nextLoc = 0;
                while (nextLoc >= 0) {
                    nextLoc = output.indexOf(LOCATION_KEY, locStart + LOCATION_KEY.length());
                    Location loc;
                    if (nextLoc < 0) {
                        loc = Location.fromUserReadableString(output.substring(locStart + LOCATION_KEY.length()));
                    } else {
                        loc = Location.fromUserReadableString(output.substring(locStart + LOCATION_KEY.length(), nextLoc));
                    }
                    if (loc.isValid()) {
                        locations.add(loc);
                    }
                    locStart = nextLoc;
                }
            }
        }
    }
    if (StringUtil.isEmpty(file)) {
        return false;
    }
    List<SourceFilePosition> sourceFilePositions = new ArrayList<SourceFilePosition>();
    File sourceFile = new File(file);
    if (locations.size() == 0) {
        messages.add(new Message(Message.Kind.ERROR, message, SourceFilePosition.UNKNOWN));
    } else {
        for (Location location : locations) {
            sourceFilePositions.add(new SourceFilePosition(sourceFile, new SourcePosition(location.startLine, location.startOffset, 0, location.endLine, location.endOffset, 0)));
        }
        SourceFilePosition first = sourceFilePositions.get(0);
        if (locations.size() == 1) {
            messages.add(new Message(Message.Kind.ERROR, message, first));
        } else {
            SourceFilePosition[] rest = new SourceFilePosition[sourceFilePositions.size() - 1];
            for (int i = 1; i < sourceFilePositions.size(); i++) {
                rest[i - 1] = sourceFilePositions.get(i);
            }
            messages.add(new Message(Message.Kind.ERROR, message, first, rest));
        }
    }
    return true;
}
Also used : SourceFilePosition(com.android.ide.common.blame.SourceFilePosition) Message(com.android.ide.common.blame.Message) SourcePosition(com.android.ide.common.blame.SourcePosition) ArrayList(java.util.ArrayList) File(java.io.File)

Aggregations

SourceFilePosition (com.android.ide.common.blame.SourceFilePosition)16 SourcePosition (com.android.ide.common.blame.SourcePosition)12 Message (com.android.ide.common.blame.Message)11 File (java.io.File)11 SourceFile (com.android.ide.common.blame.SourceFile)7 VirtualFile (com.intellij.openapi.vfs.VirtualFile)5 Matcher (java.util.regex.Matcher)4 Actions (com.android.manifmerger.Actions)3 Module (com.intellij.openapi.module.Module)3 XmlFile (com.intellij.psi.xml.XmlFile)3 NotNull (org.jetbrains.annotations.NotNull)3 MergingReport (com.android.manifmerger.MergingReport)2 GradleBuildFile (com.android.tools.idea.gradle.parser.GradleBuildFile)2 SyncMessage (com.android.tools.idea.gradle.project.sync.messages.SyncMessage)2 SyncMessageSubject.syncMessage (com.android.tools.idea.gradle.project.sync.messages.SyncMessageSubject.syncMessage)2 IdeActions (com.intellij.openapi.actionSystem.IdeActions)2 ArrayList (java.util.ArrayList)2 CompilerMessage (org.jetbrains.jps.incremental.messages.CompilerMessage)2 ParsingFailedException (com.android.ide.common.blame.parser.ParsingFailedException)1 ManifestMerger2 (com.android.manifmerger.ManifestMerger2)1