#1090 cpp parser exception with inline asm

This commit is contained in:
Andreas Dangel
2014-11-28 21:32:32 +01:00
parent 7b58836ebb
commit c8887de5ff
9 changed files with 221 additions and 1 deletions

View File

@ -3,6 +3,8 @@
*/
package net.sourceforge.pmd.cpd;
import java.util.Properties;
/**
* Defines the Language module for C/C++
*/
@ -14,4 +16,13 @@ public class CPPLanguage extends AbstractLanguage {
public CPPLanguage() {
super("C++", "cpp", new CPPTokenizer(), ".h", ".hpp", ".hxx", ".c", ".cpp", ".cxx", ".cc", ".C");
}
/* (non-Javadoc)
* @see net.sourceforge.pmd.cpd.AbstractLanguage#setProperties(java.util.Properties)
*/
@Override
public void setProperties(Properties properties) {
super.setProperties(properties);
((CPPTokenizer)getTokenizer()).setProperties(properties);
}
}

View File

@ -3,8 +3,12 @@
*/
package net.sourceforge.pmd.cpd;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.Properties;
import net.sourceforge.pmd.PMD;
import net.sourceforge.pmd.lang.LanguageRegistry;
import net.sourceforge.pmd.lang.LanguageVersionHandler;
import net.sourceforge.pmd.lang.TokenManager;
@ -19,6 +23,30 @@ import org.apache.commons.io.IOUtils;
*/
public class CPPTokenizer implements Tokenizer {
private boolean skipBlocks = true;
private String skipBlocksStart;
private String skipBlocksEnd;
/**
* Sets the possible options for the C++ tokenizer.
* @param properties the properties
* @see #OPTION_SKIP_BLOCKS
* @see #OPTION_SKIP_BLOCKS_PATTERN
*/
public void setProperties(Properties properties) {
skipBlocks = Boolean.parseBoolean(properties.getProperty(OPTION_SKIP_BLOCKS, Boolean.TRUE.toString()));
if (skipBlocks) {
String skipBlocksPattern = properties.getProperty(OPTION_SKIP_BLOCKS_PATTERN, DEFAULT_SKIP_BLOCKS_PATTERN);
String[] split = skipBlocksPattern.split("\\|", 2);
skipBlocksStart = split[0];
if (split.length == 1) {
skipBlocksEnd = split[0];
} else {
skipBlocksEnd = split[1];
}
}
}
@Override
public void tokenize(SourceCode sourceCode, Tokens tokenEntries) {
StringBuilder buffer = sourceCode.getCodeBuffer();
@ -26,7 +54,7 @@ public class CPPTokenizer implements Tokenizer {
try {
LanguageVersionHandler languageVersionHandler = LanguageRegistry.getLanguage(CppLanguageModule.NAME)
.getDefaultVersion().getLanguageVersionHandler();
reader = new StringReader(buffer.toString());
reader = new StringReader(maybeSkipBlocks(buffer.toString()));
TokenManager tokenManager = languageVersionHandler.getParser(
languageVersionHandler.getDefaultParserOptions()).getTokenManager(sourceCode.getFileName(), reader);
Token currentToken = (Token) tokenManager.getNextToken();
@ -40,8 +68,35 @@ public class CPPTokenizer implements Tokenizer {
err.printStackTrace();
System.err.println("Skipping " + sourceCode.getFileName() + " due to parse error");
tokenEntries.add(TokenEntry.getEOF());
} catch (IOException e) {
e.printStackTrace();
System.err.println("Skipping " + sourceCode.getFileName() + " due to parse error");
tokenEntries.add(TokenEntry.getEOF());
} finally {
IOUtils.closeQuietly(reader);
}
}
private String maybeSkipBlocks(String test) throws IOException {
if (!skipBlocks) {
return test;
}
BufferedReader reader = new BufferedReader(new StringReader(test));
StringBuilder filtered = new StringBuilder(test.length());
String line;
boolean skip = false;
while ((line = reader.readLine()) != null) {
if (skipBlocksStart.equalsIgnoreCase(line.trim())) {
skip = true;
} else if (skip && skipBlocksEnd.equalsIgnoreCase(line.trim())) {
skip = false;
}
if (!skip) {
filtered.append(line);
}
filtered.append(PMD.EOL); // always add a new line to keep the line-numbering
}
return filtered.toString();
}
}

View File

@ -5,8 +5,12 @@ package net.sourceforge.pmd.cpd;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.Properties;
import net.sourceforge.pmd.PMD;
import org.apache.commons.io.IOUtils;
import org.junit.Test;
public class CPPTokenizerTest {
@ -51,8 +55,43 @@ public class CPPTokenizerTest {
assertEquals(17, tokens.size());
}
@Test
public void testTokenizerWithSkipBlocks() throws Exception {
String test = IOUtils.toString(CPPTokenizerTest.class.getResourceAsStream("cpp/cpp_with_asm.cpp"));
Tokens tokens = parse(test, true);
assertEquals(19, tokens.size());
}
@Test
public void testTokenizerWithSkipBlocksPattern() throws Exception {
String test = IOUtils.toString(CPPTokenizerTest.class.getResourceAsStream("cpp/cpp_with_asm.cpp"));
Tokens tokens = parse(test, true, "#if debug|#endif");
assertEquals(31, tokens.size());
}
@Test
public void testTokenizerWithoutSkipBlocks() throws Exception {
String test = IOUtils.toString(CPPTokenizerTest.class.getResourceAsStream("cpp/cpp_with_asm.cpp"));
Tokens tokens = parse(test, false);
assertEquals(37, tokens.size());
}
private Tokens parse(String snippet) {
return parse(snippet, false);
}
private Tokens parse(String snippet, boolean skipBlocks) {
return parse(snippet, skipBlocks, null);
}
private Tokens parse(String snippet, boolean skipBlocks, String skipPattern) {
Properties properties = new Properties();
properties.setProperty(Tokenizer.OPTION_SKIP_BLOCKS, Boolean.toString(skipBlocks));
if (skipPattern != null) {
properties.setProperty(Tokenizer.OPTION_SKIP_BLOCKS_PATTERN, skipPattern);
}
CPPTokenizer tokenizer = new CPPTokenizer();
tokenizer.setProperties(properties);
SourceCode code = new SourceCode(new SourceCode.StringCodeLoader(snippet));
Tokens tokens = new Tokens();
tokenizer.tokenize(code, tokens);

View File

@ -0,0 +1,28 @@
int main() {
}
#if DEBUG
int foobar() {
}
#endif
#if 0
static void my_memset(void *dest,int fill_value,int count)
{
__asm __volatile__(
"cld\n"
"mov %ecx, %ebx\n"
"shr 2,%ecx\n"
"rep "
"stosl\n"
"mov %ebx,%ecx\n"
" // line 157 mentioned above
:
: "c" (count), "a" (fill_value), "D" (dest)
: "cc","%ebx" );
}
#endif
int otherMethod() {
}