From 08b561e41d0aace09d15435d032a208e4ed78815 Mon Sep 17 00:00:00 2001 From: Doug Schaefer Date: Fri, 6 Jan 2006 18:25:22 +0000 Subject: [PATCH] Fixes a number of Error Parser bugs where false build errors were being reported. The make, gcc, and gnu ld error parsers are now written using regex. --- .../eclipse/cdt/core/ErrorParserManager.java | 9 ++ .../errorparsers/AbstractErrorParser.java | 36 +++++ .../internal/errorparsers/ErrorPattern.java | 131 ++++++++++++++++++ .../internal/errorparsers/GCCErrorParser.java | 56 +++++++- .../internal/errorparsers/GLDErrorParser.java | 95 +++---------- .../errorparsers/MakeErrorParser.java | 97 +++++-------- 6 files changed, 284 insertions(+), 140 deletions(-) create mode 100644 core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/errorparsers/AbstractErrorParser.java create mode 100644 core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/errorparsers/ErrorPattern.java diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ErrorParserManager.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ErrorParserManager.java index e2cc57fe725..b714d729054 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ErrorParserManager.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/ErrorParserManager.java @@ -55,6 +55,8 @@ public class ErrorParserManager extends OutputStream { private StringBuffer currentLine = new StringBuffer(); private StringBuffer scratchBuffer = new StringBuffer(); + + private boolean hasErrors = false; public ErrorParserManager(ACBuilder builder) { this(builder.getProject(), builder); @@ -319,6 +321,9 @@ public class ErrorParserManager extends OutputStream { public void generateMarker(IResource file, int lineNumber, String desc, int severity, String varName) { Problem problem = new Problem(file, lineNumber, desc, severity, varName); fErrors.add(problem); + + if (severity == IMarkerGenerator.SEVERITY_ERROR_RESOURCE) + hasErrors = true; } /** @@ -461,4 +466,8 @@ public class ErrorParserManager extends OutputStream { public void clearScratchBuffer() { scratchBuffer.setLength(0); } + + public boolean hasErrors() { + return hasErrors; + } } diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/errorparsers/AbstractErrorParser.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/errorparsers/AbstractErrorParser.java new file mode 100644 index 00000000000..a67ba446566 --- /dev/null +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/errorparsers/AbstractErrorParser.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2006 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.internal.errorparsers; + +import org.eclipse.cdt.core.ErrorParserManager; +import org.eclipse.cdt.core.IErrorParser; + +/** + * @author Doug Schaefer + * + */ +public class AbstractErrorParser implements IErrorParser { + + private ErrorPattern[] patterns; + + protected AbstractErrorParser(ErrorPattern[] patterns) { + this.patterns = patterns; + } + + public boolean processLine(String line, ErrorParserManager eoParser) { + for (int i = 0; i < patterns.length; ++i) + if (patterns[i].processLine(line, eoParser)) + break; + // Should this return true if we processed a line? + return false; + } +} diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/errorparsers/ErrorPattern.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/errorparsers/ErrorPattern.java new file mode 100644 index 00000000000..b3cc1e79255 --- /dev/null +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/errorparsers/ErrorPattern.java @@ -0,0 +1,131 @@ +/******************************************************************************* + * Copyright (c) 2006 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * QNX - initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.internal.errorparsers; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.eclipse.cdt.core.ErrorParserManager; +import org.eclipse.core.resources.IFile; + +/** + * @author Doug Schaefer + * + */ +public class ErrorPattern { + private final Pattern pattern; + private final int groupFileName; + private final int groupLineNum; + private final int groupDesc; + private final int groupVarName; + private final int severity; + + /** + * Full Pattern Constructor. + * + * @param pattern + * @param groupFileName + * @param groupLineNum + * @param groupDesc + * @param groupVarName + * @param severity + */ + public ErrorPattern(String pattern, + int groupFileName, + int groupLineNum, + int groupDesc, + int groupVarName, + int severity) { + this.pattern = Pattern.compile(pattern); + this.groupFileName = groupFileName; + this.groupLineNum = groupLineNum; + this.groupDesc = groupDesc; + this.groupVarName = groupVarName; + this.severity = severity; + } + + /** + * Pattern for errors not associated file a file + * (e.g. make and linker errors). + * + * @param pattern + * @param groupDesc + * @param severity + */ + public ErrorPattern(String pattern, int groupDesc, int severity) { + this(pattern, 0, 0, groupDesc, 0, severity); + } + + public Matcher getMatcher(CharSequence input) { + return pattern.matcher(input); + } + + public String getFileName(Matcher matcher) { + return groupFileName != 0 ? matcher.group(groupFileName) : null; + } + + public int getLineNum(Matcher matcher) { + try { + return groupLineNum != 0 + ? Integer.valueOf(matcher.group(groupLineNum)) + : 0; + } catch (NumberFormatException e) { + return 0; + } + } + + public String getDesc(Matcher matcher) { + return groupDesc != 0 ? matcher.group(groupDesc) : null; + } + + public String getVarName(Matcher matcher) { + return groupVarName != 0 ? matcher.group(groupVarName) : null; + } + + public int getSeverity(Matcher matcher) { + return severity; + } + + public boolean processLine(String line, ErrorParserManager eoParser) { + Matcher matcher = getMatcher(line); + if (!matcher.find()) + return false; + + return recordError(matcher, eoParser); + } + + protected boolean recordError(Matcher matcher, ErrorParserManager eoParser) { + String fileName = getFileName(matcher); + int lineNum = getLineNum(matcher); + String desc = getDesc(matcher); + String varName = getVarName(matcher); + int severity = getSeverity(matcher); + + IFile file = null; + if (fileName != null) { + file = eoParser.findFileName(fileName); + if (file != null) { + if (eoParser.isConflictingName(fileName)) { + file = null; + } + } else { + file = eoParser.findFilePath(fileName); + } + if (file == null) { + desc = fileName + " " + desc; //$NON-NLS-1$ + } + } + + eoParser.generateMarker(file, lineNum, desc, severity, varName); + return true; + } +} diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/errorparsers/GCCErrorParser.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/errorparsers/GCCErrorParser.java index 5d8590fdd7b..09d40e07220 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/errorparsers/GCCErrorParser.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/errorparsers/GCCErrorParser.java @@ -11,16 +11,66 @@ package org.eclipse.cdt.internal.errorparsers; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + import org.eclipse.cdt.core.ErrorParserManager; -import org.eclipse.cdt.core.IErrorParser; import org.eclipse.cdt.core.IMarkerGenerator; import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; -public class GCCErrorParser implements IErrorParser { +public class GCCErrorParser extends AbstractErrorParser { - public boolean processLine(String line, ErrorParserManager eoParser) { + private static final Pattern[] varPatterns = { + Pattern.compile("'(.*)' undeclared"), + Pattern.compile("'(.*)' defined but not used"), + Pattern.compile("conflicting types for '(.*)'"), + Pattern.compile("parse error before '(.*)'") + }; + + private static final ErrorPattern[] patterns = { + new ErrorPattern("\\(Each undeclared identifier is reported only once", 0, 0) { + protected boolean recordError(Matcher matcher, ErrorParserManager eoParser) { + // Skip this one + return true; + } + }, + new ErrorPattern("for each function it appears in.\\)", 0, 0) { + protected boolean recordError(Matcher matcher, ErrorParserManager eoParser) { + // Skip this one + return true; + } + }, + new ErrorPattern("((.:)?.*):([0-9]*)(:(0-9)*)?: ([Ww]arning: )?(.*)", 1, 3, 7, 0, 0) { + public String getVarName(Matcher matcher) { + String desc = getDesc(matcher); + Matcher varMatcher = null; + for (int i = 0; i < varPatterns.length; ++i) { + varMatcher = varPatterns[i].matcher(desc); + if (varMatcher.find()) + break; + else + varMatcher = null; + } + + return varMatcher != null ? varMatcher.group(1) : null; + } + public int getSeverity(Matcher matcher) { + String warningGroup = matcher.group(6); + if (warningGroup != null) + return IMarkerGenerator.SEVERITY_WARNING; + else + return IMarkerGenerator.SEVERITY_ERROR_RESOURCE; + } + } + }; + + public GCCErrorParser() { + super(patterns); + } + + public boolean processLine0(String line, ErrorParserManager eoParser) { return processLine(line, eoParser, IMarkerGenerator.SEVERITY_ERROR_RESOURCE); } diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/errorparsers/GLDErrorParser.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/errorparsers/GLDErrorParser.java index 85898e2dde5..80b255a3df4 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/errorparsers/GLDErrorParser.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/errorparsers/GLDErrorParser.java @@ -11,87 +11,28 @@ package org.eclipse.cdt.internal.errorparsers; -import org.eclipse.cdt.core.ErrorParserManager; -import org.eclipse.cdt.core.IErrorParser; +import java.util.regex.Matcher; + import org.eclipse.cdt.core.IMarkerGenerator; -import org.eclipse.core.resources.IFile; -import org.eclipse.core.runtime.Path; -public class GLDErrorParser implements IErrorParser { +public class GLDErrorParser extends AbstractErrorParser { - public boolean processLine(String line, ErrorParserManager eoParser) { - // binutils linker error: - // 1- an error when trying to link - // tempfile: In function `function': - // tempfile(.text+0xhex): undefined reference to `symbol' - // 2- - // Something went wrong check if it is "ld" the linkeer bay cheching - // the last letter for "ld" - // An example might be (not all are warnings): - // ntox86-ld: warning: libcpp.so.2, needed by C:/temp//libdisplay.so, may conflict with libcpp.so.3 - int firstColon= line.indexOf(':'); - if (firstColon != -1) { - String buf= line.substring(0, firstColon); - String desc= line.substring(firstColon + 1); - int firstPara= buf.indexOf('('); - int secondPara= buf.indexOf(')'); - if (firstPara >= 0 && secondPara >= 0) { - String fileName = buf.substring(0, firstPara); - String previous = eoParser.getPreviousLine(); - if (previous == null) - previous = ""; //$NON-NLS-1$ - int colon = previous.indexOf(':'); - if (colon != -1) { - previous = previous.substring(colon + 1); - } - - // The pattern is to generall we have to guard: - // Before making this pattern a marker we do one more check - // The fileName that we extract __must__ look like a valid file name. - // We been having to much bad hits with patterns like - // /bin/sh ../libtool --mode=link gcc -version-info 0:1:0 foo.lo var.lo - // Things like libtool that will fool the parser because of "0:1:0" - if (!Path.EMPTY.isValidPath(fileName)) { - return false; - } - - desc = "*" + previous + " " + desc; //$NON-NLS-1$ //$NON-NLS-2$ - IFile file = eoParser.findFileName(fileName); - if (file != null) { - if (eoParser.isConflictingName(fileName)) { - file = null; - } - } else { - file = eoParser.findFilePath(fileName); - } - if (file == null) { - desc = fileName + " " + desc; //$NON-NLS-1$ - } - eoParser.generateMarker(file, 0, desc, IMarkerGenerator.SEVERITY_ERROR_RESOURCE, null); - } else if (buf.endsWith("ld")){ //$NON-NLS-1$ - // By default treat the condition as fatal/error, unless marked as a warning - int errorType = IMarkerGenerator.SEVERITY_ERROR_RESOURCE; - desc = desc.trim(); - if(desc.startsWith("warning") || desc.startsWith("Warning")) { //$NON-NLS-1$ //$NON-NLS-2$ - errorType = IMarkerGenerator.SEVERITY_WARNING; - } - - String fileName = line.substring(0, firstColon); - IFile file = eoParser.findFileName(fileName); - if (file != null) { - if (eoParser.isConflictingName(fileName)) { - file = null; - } - } else { - file = eoParser.findFilePath(fileName); - } - if (file == null) { - desc = fileName + " " + desc; //$NON-NLS-1$ - } - - eoParser.generateMarker(file, 0, desc, errorType, null); + private static final ErrorPattern[] patterns = { + new ErrorPattern("(.*)\\(\\.text\\+.*\\): (.*)", 1, 0, 2, 0, IMarkerGenerator.SEVERITY_ERROR_RESOURCE), //$NON-NLS-1 + new ErrorPattern("ld(\\.exe)?: ([Ww]arning .*)", 2, IMarkerGenerator.SEVERITY_WARNING), //$NON-NLS-1 + new ErrorPattern("ld(\\.exe)?: (.*)", 0, IMarkerGenerator.SEVERITY_ERROR_RESOURCE) { //$NON-NLS-1 + public String getDesc(Matcher matcher) { + // add in the name of the link command to give it some context + StringBuffer buff = new StringBuffer(); + buff.append("ld: "); //$NON-NLS-1$ + buff.append(matcher.group(2)); + return buff.toString(); } } - return false; + }; + + public GLDErrorParser() { + super(patterns); } + } diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/errorparsers/MakeErrorParser.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/errorparsers/MakeErrorParser.java index 38ab4a00dc3..e941d198683 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/errorparsers/MakeErrorParser.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/errorparsers/MakeErrorParser.java @@ -11,71 +11,48 @@ package org.eclipse.cdt.internal.errorparsers; +import java.util.regex.Matcher; + import org.eclipse.cdt.core.ErrorParserManager; -import org.eclipse.cdt.core.IErrorParser; import org.eclipse.cdt.core.IMarkerGenerator; import org.eclipse.core.runtime.Path; -public class MakeErrorParser implements IErrorParser { - +public class MakeErrorParser extends AbstractErrorParser { + + private static final ErrorPattern[] patterns = { + new ErrorPattern("make\\[(.*)\\]: Entering directory `(.*)'", 0, 0) { //$NON-NLS-1 + protected boolean recordError(Matcher matcher, ErrorParserManager eoParser) { + int level = Integer.valueOf(matcher.group(1)); + String dir = matcher.group(2); + /* Sometimes make screws up the output, so + * "leave" events can't be seen. Double-check level + * here. + */ + int parseLevel = eoParser.getDirectoryLevel(); + for (; level < parseLevel; level++) { + eoParser.popDirectory(); + } + eoParser.pushDirectory(new Path(dir)); + return true; + } + }, + new ErrorPattern("make\\[.*\\]: Leaving directory", 0, 0) { //$NON-NLS-1 + protected boolean recordError(Matcher matcher, ErrorParserManager eoParser) { + eoParser.popDirectory(); + return true; + } + }, + new ErrorPattern("(make: \\*\\*\\* \\[.*\\] Error .*)", 1, IMarkerGenerator.SEVERITY_ERROR_RESOURCE) { //$NON-NLS-1 + protected boolean recordError(Matcher matcher, ErrorParserManager eoParser) { + if (!eoParser.hasErrors()) + super.recordError(matcher, eoParser); + return true; + } + } + }; + public MakeErrorParser() { + super(patterns); } - static int getDirectoryLevel(String line) { - int s = line.indexOf('['); - int num = 0; - if (s != -1) { - int e = line.indexOf(']'); - String number = line.substring(s + 1, e).trim(); - try { - num = Integer.parseInt(number); - } catch (NumberFormatException exc) { - } - } - return num; - } - - public boolean processLine(String line, ErrorParserManager eoParser) { - // make\[[0-9]*\]: error_desc - int firstColon= line.indexOf(':'); - if (firstColon != -1 && line.startsWith("make")) { //$NON-NLS-1$ - boolean enter = false; - String msg= line.substring(firstColon + 1).trim(); - if ((enter = msg.startsWith("Entering directory")) || //$NON-NLS-1$ - (msg.startsWith("Leaving directory"))) { //$NON-NLS-1$ - int s = msg.indexOf('`'); - int e = msg.indexOf('\''); - if (s != -1 && e != -1) { - String dir = msg.substring(s+1, e); - if (enter) { - /* Sometimes make screws up the output, so - * "leave" events can't be seen. Double-check level - * here. - */ - int level = getDirectoryLevel(line); - int parseLevel = eoParser.getDirectoryLevel(); - for (; level < parseLevel; level++) { - eoParser.popDirectory(); - } - eoParser.pushDirectory(new Path(dir)); - } else { - eoParser.popDirectory(); - /* Could check to see if they match */ - } - } - } else if (msg.startsWith("***")) { //$NON-NLS-1$ - boolean warning = false; - if (msg.length() > 4) { - String s = msg.substring(3).trim(); - warning = s.startsWith("Warning"); //$NON-NLS-1$ - } - if (warning) { - eoParser.generateMarker(null, -1, msg, IMarkerGenerator.SEVERITY_WARNING, null); - } else { - eoParser.generateMarker(null, -1, msg, IMarkerGenerator.SEVERITY_ERROR_BUILD, null); - } - } - } - return false; - } }