internal void ParseVBErrorOrWarning(string singleLine, MessageImportance messageImportance) { if (this.vbErrorLines.Count > 0) { if (!this.isDoneOutputtingErrorMessage && (singleLine.Length == 0)) { this.isDoneOutputtingErrorMessage = true; this.numberOfLinesInErrorMessage = this.vbErrorLines.Count; } this.vbErrorLines.Enqueue(new VBError(singleLine, messageImportance)); if (this.isDoneOutputtingErrorMessage && (this.vbErrorLines.Count == (this.numberOfLinesInErrorMessage + 3))) { VBError error = this.vbErrorLines.Dequeue(); string message = error.Message; int num = singleLine.IndexOf('~') + 1; int index = message.IndexOf(')'); if ((num < 0) || (index < 0)) { base.Log.LogMessageFromText(message, error.MessageImportance); foreach (VBError error2 in this.vbErrorLines) { base.LogEventsFromTextOutput(error2.Message, error2.MessageImportance); } this.vbErrorLines.Clear(); } else { string lineOfText = null; lineOfText = string.Concat(new object[] { message.Substring(0, index), ",", num, message.Substring(index) }); base.Log.LogMessageFromText(lineOfText, error.MessageImportance); foreach (VBError error3 in this.vbErrorLines) { base.LogEventsFromTextOutput(error3.Message, error3.MessageImportance); } this.vbErrorLines.Clear(); } } } else { Microsoft.Build.Utilities.CanonicalError.Parts parts = Microsoft.Build.Utilities.CanonicalError.Parse(singleLine); if (parts == null) { base.LogEventsFromTextOutput(singleLine, messageImportance); } else if (((parts.category == Microsoft.Build.Utilities.CanonicalError.Parts.Category.Error) || (parts.category == Microsoft.Build.Utilities.CanonicalError.Parts.Category.Warning)) && (parts.column == 0)) { if (parts.line != 0) { this.vbErrorLines.Enqueue(new VBError(singleLine, messageImportance)); this.isDoneOutputtingErrorMessage = false; this.numberOfLinesInErrorMessage = 0; } else { base.LogEventsFromTextOutput(singleLine, messageImportance); } } } }
/// <summary> /// Given a string, parses it to find out whether it's an error or warning and, if so, /// make sure it's validated properly. /// </summary> /// <comments> /// INTERNAL FOR UNITTESTING ONLY /// </comments> /// <param name="singleLine">The line to parse</param> /// <param name="messageImportance">The MessageImportance to use when reporting the error.</param> internal void ParseVBErrorOrWarning(string singleLine, MessageImportance messageImportance) { // if this string is empty then we haven't seen the first line of an error yet if (_vbErrorLines.Count > 0) { // vbc separates the error message from the source text with an empty line, so // we can check for an empty line to see if vbc finished outputting the error message if (!_isDoneOutputtingErrorMessage && singleLine.Length == 0) { _isDoneOutputtingErrorMessage = true; _numberOfLinesInErrorMessage = _vbErrorLines.Count; } _vbErrorLines.Enqueue(new VBError(singleLine, messageImportance)); // We are looking for the line that indicates the column (contains the '~'), // which vbc outputs 3 lines below the error message: // // <error message> // <blank line> // <line with the source text> // <line with the '~'> if (_isDoneOutputtingErrorMessage && _vbErrorLines.Count == _numberOfLinesInErrorMessage + 3) { // Once we have the 4th line (error line + 3), then parse it for the first ~ // which will correspond to the column of the token with the error because // VBC respects the users's indentation settings in the file it is compiling // and only outputs SPACE chars to STDOUT. // The +1 is to translate the index into user columns which are 1 based. VBError originalVBError = _vbErrorLines.Dequeue(); string originalVBErrorString = originalVBError.Message; int column = singleLine.IndexOf('~') + 1; int endParenthesisLocation = originalVBErrorString.IndexOf(')'); // If for some reason the line does not contain any ~ then something went wrong // so abort and return the origional string. if (column < 0 || endParenthesisLocation < 0) { // we need to output all of the original lines we ate. Log.LogMessageFromText(originalVBErrorString, originalVBError.MessageImportance); foreach (VBError vberror in _vbErrorLines) { base.LogEventsFromTextOutput(vberror.Message, vberror.MessageImportance); } _vbErrorLines.Clear(); return; } string newLine = null; newLine = originalVBErrorString.Substring(0, endParenthesisLocation) + "," + column + originalVBErrorString.Substring(endParenthesisLocation); // Output all of the lines of the error, but with the modified first line as well. Log.LogMessageFromText(newLine, originalVBError.MessageImportance); foreach (VBError vberror in _vbErrorLines) { base.LogEventsFromTextOutput(vberror.Message, vberror.MessageImportance); } _vbErrorLines.Clear(); } } else { CanonicalError.Parts parts = CanonicalError.Parse(singleLine); if (parts == null) { base.LogEventsFromTextOutput(singleLine, messageImportance); } else if ((parts.category == CanonicalError.Parts.Category.Error || parts.category == CanonicalError.Parts.Category.Warning) && parts.column == CanonicalError.Parts.numberNotSpecified) { if (parts.line != CanonicalError.Parts.numberNotSpecified) { // If we got here, then this is a standard VBC error or warning. _vbErrorLines.Enqueue(new VBError(singleLine, messageImportance)); _isDoneOutputtingErrorMessage = false; _numberOfLinesInErrorMessage = 0; } else { // Project-level errors don't have line numbers -- just output now. base.LogEventsFromTextOutput(singleLine, messageImportance); } } } }