mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-23 22:52:11 +02:00
Bug 433171 - Handle line continuations when parsing build output
Change-Id: I9449e3167eae1464d23948da80663997adf95b16 Signed-off-by: Nathan Ridge <zeratul976@hotmail.com>
This commit is contained in:
parent
676f150755
commit
ff5a55388c
2 changed files with 89 additions and 0 deletions
|
@ -1130,6 +1130,51 @@ public class GCCBuildCommandParserTest extends BaseTestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test use of a line-continuation character ('\') in build output.
|
||||||
|
*/
|
||||||
|
public void testLineContinuation() throws Exception {
|
||||||
|
// Create model project and accompanied descriptions
|
||||||
|
String projectName = getName();
|
||||||
|
IProject project = ResourceHelper.createCDTProjectWithConfig(projectName);
|
||||||
|
ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project);
|
||||||
|
ICConfigurationDescription cfgDescription = cfgDescriptions[0];
|
||||||
|
|
||||||
|
IFile file0=ResourceHelper.createFile(project, "file0.cpp");
|
||||||
|
IFile file1=ResourceHelper.createFile(project, "file1.cpp");
|
||||||
|
IFile file2=ResourceHelper.createFile(project, "file2.cpp");
|
||||||
|
ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(file0.getProjectRelativePath(), true);
|
||||||
|
String languageId = ls.getLanguageId();
|
||||||
|
|
||||||
|
// create GCCBuildCommandParser
|
||||||
|
GCCBuildCommandParser parser = (GCCBuildCommandParser) LanguageSettingsManager.getExtensionProviderCopy(GCC_BUILD_COMMAND_PARSER_EXT, true);
|
||||||
|
|
||||||
|
// parse line
|
||||||
|
parser.startup(cfgDescription, null);
|
||||||
|
parser.processLine("gcc file0.cpp -I/path0 \\");
|
||||||
|
parser.processLine(" -I/path1");
|
||||||
|
parser.processLine("gcc file1.cpp -I/path0 \\\\"); // not a continuation, '\' is escaped!
|
||||||
|
parser.processLine(" -I/path1");
|
||||||
|
parser.processLine("gcc file2.cpp -I/path0 \\"); // continuation at end of last line
|
||||||
|
parser.shutdown();
|
||||||
|
|
||||||
|
// check populated entries
|
||||||
|
{
|
||||||
|
List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file0, languageId);
|
||||||
|
assertEquals(new CIncludePathEntry("/path0", 0), entries.get(0));
|
||||||
|
assertEquals(new CIncludePathEntry("/path1", 0), entries.get(1));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file1, languageId);
|
||||||
|
assertEquals(new CIncludePathEntry("/path0", 0), entries.get(0));
|
||||||
|
assertEquals(1, entries.size());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
List<ICLanguageSettingEntry> entries = parser.getSettingEntries(cfgDescription, file2, languageId);
|
||||||
|
assertEquals(new CIncludePathEntry("/path0", 0), entries.get(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test parsing of paths located on a different drive on Windows.
|
* Test parsing of paths located on a different drive on Windows.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -70,6 +70,9 @@ public abstract class AbstractBuildCommandParser extends AbstractLanguageSetting
|
||||||
|
|
||||||
// cached value from properties, do not need to use in equals() and hashCode()
|
// cached value from properties, do not need to use in equals() and hashCode()
|
||||||
private ResourceScope resourceScope = null;
|
private ResourceScope resourceScope = null;
|
||||||
|
|
||||||
|
// Used to handle line continuations in the build output.
|
||||||
|
private String partialLine;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The compiler command pattern without specifying compiler options.
|
* The compiler command pattern without specifying compiler options.
|
||||||
|
@ -241,9 +244,50 @@ public abstract class AbstractBuildCommandParser extends AbstractLanguageSetting
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void shutdown() {
|
public void shutdown() {
|
||||||
|
// If there's an unprocessed partial line (because the last line of the build output ended
|
||||||
|
// in a line-continuation character), process it.
|
||||||
|
if (partialLine != null) {
|
||||||
|
processLine(partialLine);
|
||||||
|
partialLine = null;
|
||||||
|
}
|
||||||
|
|
||||||
serializeLanguageSettingsInBackground();
|
serializeLanguageSettingsInBackground();
|
||||||
super.shutdown();
|
super.shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean processLine(String line) {
|
||||||
|
line = handleLineContinuation(line);
|
||||||
|
return super.processLine(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle line continuations ('\' at the end of a line, indicating that the next line is a
|
||||||
|
* continuation of this one).
|
||||||
|
*/
|
||||||
|
private String handleLineContinuation(String line) {
|
||||||
|
if (line == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// If the character preceding the '\' is also '\', it's not a line continuation -
|
||||||
|
// the first '\' escapes the second.
|
||||||
|
if (line.length() > 0 && line.charAt(line.length() - 1) == '\\' &&
|
||||||
|
(line.length() == 1 || line.charAt(line.length() - 2) != '\\')) {
|
||||||
|
// Line ends in line continuation - save it for later.
|
||||||
|
String fragment = line.substring(0, line.length() - 1);
|
||||||
|
if (partialLine == null) {
|
||||||
|
partialLine = fragment;
|
||||||
|
} else {
|
||||||
|
partialLine += fragment;
|
||||||
|
}
|
||||||
|
return null; // line will not be processed now
|
||||||
|
} else if (partialLine != null) {
|
||||||
|
// Line doesn't end in continuation but previous lines did - use their contents.
|
||||||
|
line = partialLine + line;
|
||||||
|
partialLine = null;
|
||||||
|
}
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Trivial Error Parser which allows highlighting of output lines matching the patterns
|
* Trivial Error Parser which allows highlighting of output lines matching the patterns
|
||||||
|
|
Loading…
Add table
Reference in a new issue