/**
* Creates a code reader with specific configuration parameters.
* Note that this constructor will read everything from reader and will close it.
- *
+ *
* @param code
* the Reader to read code from
* @param configuration
/**
* Creates a code reader with specific configuration parameters.
- *
+ *
* @param code
* the code itself
* @param configuration
/**
* Read and consume the next character
- *
+ *
* @param appendable
* the read character is appended to appendable
*/
/**
* Read without consuming the next characters
- *
+ *
* @param length
* number of character to read
* @return array of characters
/**
* Read without consuming the next characters until a condition is reached (EndMatcher)
- *
+ *
* @param matcher
* the EndMatcher used to stop the reading
* @param appendable
int index = 0;
char nextChar = charAt(index);
try {
- while ( !matcher.match(nextChar) && nextChar != -1) {
+ while (!matcher.match(nextChar) && nextChar != -1) {
appendable.append(nextChar);
nextChar = charAt(++index);
}
try {
do {
appendable.append((char) pop());
- } while ( !matcher.match(peek()) && peek() != -1);
+ } while (!matcher.match(peek()) && peek() != -1);
} catch (IOException e) {
throw new ChannelException(e.getMessage(), e);
}
/**
* Read and consume the next characters according to a given regular expression
- *
+ *
* @param matcher
* the regular expression matcher
* @param appendable
/**
* Read and consume the next characters according to a given regular expression. Moreover the character sequence immediately following the
* desired characters must also match a given regular expression.
- *
+ *
* @param matcher
* the Matcher used to try consuming next characters
* @param afterMatcher
if (afterMatcher != null) {
afterMatcher.reset(this);
afterMatcher.region(matcher.end(), length());
- if ( !afterMatcher.lookingAt()) {
+ if (!afterMatcher.lookingAt()) {
return -1;
}
}
}
return matcher.end();
}
+ } catch (StackOverflowError e) {
+ throw new ChannelException("Unable to apply regular expression '" + matcher.pattern().pattern()
+ + "' at line " + getCursor().getLine() + " and column " + getCursor().getColumn()
+ + ", because it led to a stack overflow error."
+ + " This error may be due to an inefficient use of alternations - see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5050507");
} catch (IndexOutOfBoundsException e) {
return -1;
} catch (IOException e) {
private final StringBuilder tmpBuilder = new StringBuilder();
private final Matcher matcher;
- private final String regex;
/**
* Create a RegexChannel object with the required regular expression
- *
+ *
* @param regex
* regular expression to be used to try matching the next characters in the stream
*/
public RegexChannel(String regex) {
matcher = Pattern.compile(regex).matcher("");
- this.regex = regex;
}
@Override
public final boolean consume(CodeReader code, OUTPUT output) {
- try {
- if (code.popTo(matcher, tmpBuilder) > 0) {
- consume(tmpBuilder, output);
- tmpBuilder.delete(0, tmpBuilder.length());
- return true;
- }
- return false;
- } catch (StackOverflowError e) {
- throw new IllegalArgumentException(
- "The regular expression "
- + regex
- + " has led to a stack overflow error. "
- + "This error is certainly due to an inefficient use of alternations. See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5050507",
- e);
+ if (code.popTo(matcher, tmpBuilder) > 0) {
+ consume(tmpBuilder, output);
+ tmpBuilder.delete(0, tmpBuilder.length());
+ return true;
}
+ return false;
}
/**
* The consume method is called each time the regular expression used to create the RegexChannel object matches the next characters in the
* character streams.
- *
+ *
* @param token
* the token consumed in the character stream and matching the regular expression
* @param the
* OUPUT object which can be optionally fed
*/
protected abstract void consume(CharSequence token, OUTPUT output);
+
}
*/
package org.sonar.channel;
-import static org.hamcrest.core.Is.is;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
import java.io.StringReader;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import org.junit.Test;
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
public class CodeReaderTest {
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
@Test
public void testPopWithAppendable() {
CodeReader reader = new CodeReader("package org.sonar;");
assertEquals( -1, reader.popTo(Pattern.compile("\\w+").matcher(new String()), token));
}
+ @Test
+ public void test() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("\n");
+ for (int i = 0; i < 10000; i++) {
+ sb.append(Integer.toHexString(i));
+ }
+ CodeReader reader = new CodeReader(sb.toString());
+ reader.pop();
+ reader.pop();
+
+ thrown.expect(ChannelException.class);
+ thrown.expectMessage("Unable to apply regular expression '([a-fA-F]|\\d)+' at line 2 and column 1," +
+ " because it led to a stack overflow error." +
+ " This error may be due to an inefficient use of alternations - see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5050507");
+ reader.popTo(Pattern.compile("([a-fA-F]|\\d)+").matcher(""), new StringBuilder());
+ }
+
@Test
public void testPopToWithRegexAndFollowingMatcher() {
Matcher digitMatcher = Pattern.compile("\\d+").matcher(new String());