Move cpp into own sub-module

This commit is contained in:
Andreas Dangel
2014-10-04 18:48:35 +02:00
parent 802af053cf
commit cdf293f9fc
15 changed files with 233 additions and 19 deletions

1591
pmd-cpp/etc/grammar/cpp.jj Normal file

File diff suppressed because it is too large Load Diff

185
pmd-cpp/pom.xml Normal file
View File

@ -0,0 +1,185 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>pmd-cpp</artifactId>
<name>PMD C++</name>
<parent>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd-aggregate</artifactId>
<version>5.1.4-SNAPSHOT</version>
</parent>
<build>
<plugins>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<useDefaultDelimiters>false</useDefaultDelimiters>
<delimiters>
<delimiter>${*}</delimiter>
</delimiters>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<inherited>true</inherited>
<executions>
<execution>
<id>generate-sources</id>
<phase>generate-sources</phase>
<configuration>
<target>
<ant antfile="src/main/ant/alljavacc.xml">
<property name="target" value="${project.build.directory}/generated-sources/javacc" />
<property name="javacc.jar" value="${settings.localRepository}/net/java/dev/javacc/javacc/${javacc.version}/javacc-${javacc.version}.jar" />
</ant>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<executions>
<execution>
<id>add-javacc-generated-sources</id>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>${project.build.directory}/generated-sources/javacc</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
<!-- As Clover can be quite an hassle, know that you can skip
it by using the following option when running mvn: $ mvn clean -Dmaven.clover.skip=true
site -->
<plugin>
<groupId>com.atlassian.maven.plugins</groupId>
<artifactId>maven-clover2-plugin</artifactId>
<configuration>
<jdk>${java.version}</jdk>
<licenseLocation>${basedir}/../pmd/licences/clover2.license</licenseLocation>
</configuration>
<executions>
<execution>
<phase>pre-site</phase>
<goals>
<goal>instrument</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-site-plugin</artifactId>
<configuration>
<xdocDirectory>${project.build.directory}/generated-xdocs</xdocDirectory>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd-test</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.ant</groupId>
<artifactId>ant</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.ant</groupId>
<artifactId>ant-testutil</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<exclusions>
<exclusion>
<artifactId>xercesImpl</artifactId>
<groupId>xerces</groupId>
</exclusion>
<exclusion>
<artifactId>xalan</artifactId>
<groupId>xalan</groupId>
</exclusion>
<exclusion>
<artifactId>icu4j</artifactId>
<groupId>com.ibm.icu</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.beust</groupId>
<artifactId>jcommander</artifactId>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
</dependency>
<dependency>
<groupId>net.sourceforge.saxon</groupId>
<artifactId>saxon</artifactId>
</dependency>
<dependency>
<groupId>net.sourceforge.saxon</groupId>
<artifactId>saxon</artifactId>
<classifier>dom</classifier>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>xerces</groupId>
<artifactId>xercesImpl</artifactId>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.java.dev.javacc</groupId>
<artifactId>javacc</artifactId>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,45 @@
<project name="pmd" default="alljavacc" basedir="../../">
<property name="javacc-home.path" value="target/lib" />
<target name="alljavacc"
description="Generates all JavaCC aspects within PMD"
depends="checkUpToDate,init,cppjavacc,cleanup" />
<target name="checkUpToDate">
<uptodate property="javaccBuildNotRequired" targetfile="${target}/last-generated-timestamp">
<srcfiles dir="etc/grammar" includes="*.jj*"/>
</uptodate>
<echo message="up to date check: javaccBuildNotRequired=${javaccBuildNotRequired}"/>
</target>
<target name="init" unless="javaccBuildNotRequired">
<mkdir dir="${javacc-home.path}" />
<copy file="${javacc.jar}" tofile="${javacc-home.path}/javacc.jar" />
<mkdir dir="${target}"/>
<touch file="${target}/last-generated-timestamp"/>
</target>
<target name="cleanup">
<delete dir="${javacc-home.path}" />
</target>
<target name="cppjavacc" description="Generates the C++ grammar" unless="javaccBuildNotRequired">
<delete dir="${target}/net/sourceforge/pmd/lang/cpp/ast" />
<mkdir dir="${target}/net/sourceforge/pmd/lang/cpp/ast" />
<!-- Ensure generated using CharStream interface -->
<javacc static="false"
usercharstream="true"
target="etc/grammar/cpp.jj"
outputdirectory="${target}/net/sourceforge/pmd/lang/cpp/ast"
javacchome="${javacc-home.path}" />
<replace file="${target}/net/sourceforge/pmd/lang/cpp/ast/CppParserTokenManager.java"
token="class CppParserTokenManager"
value="class CppParserTokenManager extends net.sourceforge.pmd.lang.ast.AbstractTokenManager" />
<delete file="${target}/net/sourceforge/pmd/lang/cpp/ast/CharStream.java" />
<delete file="${target}/net/sourceforge/pmd/lang/cpp/ast/ParseException.java" />
<delete file="${target}/net/sourceforge/pmd/lang/cpp/ast/TokenMgrError.java" />
</target>
</project>

View File

@ -0,0 +1,10 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.cpd;
public class CPPLanguage extends AbstractLanguage {
public CPPLanguage() {
super(new CPPTokenizer(), ".h", ".hpp", ".hxx",".c", ".cpp", ".cxx", ".cc", ".C");
}
}

View File

@ -0,0 +1,43 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.cpd;
import java.io.StringReader;
import net.sourceforge.pmd.lang.LanguageRegistry;
import net.sourceforge.pmd.lang.LanguageVersionHandler;
import net.sourceforge.pmd.lang.TokenManager;
import net.sourceforge.pmd.lang.ast.TokenMgrError;
import net.sourceforge.pmd.lang.cpp.CppLanguageModule;
import net.sourceforge.pmd.lang.cpp.ast.Token;
import org.apache.commons.io.IOUtils;
public class CPPTokenizer implements Tokenizer {
public void tokenize(SourceCode sourceCode, Tokens tokenEntries) {
StringBuilder buffer = sourceCode.getCodeBuffer();
StringReader reader = null;
try {
LanguageVersionHandler languageVersionHandler = LanguageRegistry.getLanguage(CppLanguageModule.NAME).getDefaultVersion().getLanguageVersionHandler();
reader = new StringReader(buffer.toString());
TokenManager tokenManager = languageVersionHandler.getParser(
languageVersionHandler.getDefaultParserOptions())
.getTokenManager(sourceCode.getFileName(), reader);
Token currentToken = (Token) tokenManager.getNextToken();
while (currentToken.image.length() > 0) {
tokenEntries.add(new TokenEntry(currentToken.image, sourceCode.getFileName(), currentToken.beginLine));
currentToken = (Token) tokenManager.getNextToken();
}
tokenEntries.add(TokenEntry.getEOF());
System.err.println("Added " + sourceCode.getFileName());
} catch (TokenMgrError err) {
err.printStackTrace();
System.err.println("Skipping " + sourceCode.getFileName() + " due to parse error");
tokenEntries.add(TokenEntry.getEOF());
} finally {
IOUtils.closeQuietly(reader);
}
}
}

View File

@ -0,0 +1,78 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.cpp;
import java.io.IOException;
import java.io.PushbackReader;
import java.io.Reader;
/**
* A custom {@link Reader} which completely omits C/C++ continuation character
* sequences from an underlying reader. Specifically the sequences {@code \ \n}
* (backslash, carriage return), or {@code \ \r \n} (backslash, line feed,
* carriage return).
* <p>
* This reader exists because to modify a JavaCC lexer to understand arbitrary
* continuations inside of any token is cumbersome, and just removing them from
* the input entirely is easier to implement. See this discussion on the JavaCC
* mailing list on <a href=
* "http://java.net/projects/javacc/lists/users/archive/2005-06/message/16">line
* continuation character</a>.
*/
public class ContinuationReader extends Reader {
private static final int EOF = -1;
private static final char BACKSLASH = '\\';
private static final char CARRIAGE_RETURN = '\n';
private static final char LINE_FEED = '\r';
protected final PushbackReader in;
public ContinuationReader(Reader in) {
this.in = new PushbackReader(in, 2);
}
@Override
public int read(char[] cbuf, int off, int len) throws IOException {
int count = 0;
while (count < len) {
int c1 = in.read();
if (c1 == EOF) {
break;
} else if (c1 == BACKSLASH) {
int c2 = in.read();
if (c2 == EOF) {
// No match
} else if (c2 == CARRIAGE_RETURN) {
// Match: backslash, carriage return
continue;
} else if (c2 == LINE_FEED) {
int c3 = in.read();
if (c3 == EOF) {
// No match
in.unread(c2);
} else if (c3 == CARRIAGE_RETURN) {
// Match: backslash, line feed, carriage return
continue;
} else {
// No match
in.unread(c3);
in.unread(c2);
}
} else {
// No match
in.unread(c2);
}
}
cbuf[off + count] = (char) c1;
count++;
}
return count > 0 ? count : -1;
}
@Override
public void close() throws IOException {
in.close();
}
}

View File

@ -0,0 +1,23 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.cpp;
import net.sourceforge.pmd.lang.AbstractLanguageVersionHandler;
import net.sourceforge.pmd.lang.Parser;
import net.sourceforge.pmd.lang.ParserOptions;
import net.sourceforge.pmd.lang.rule.RuleViolationFactory;
/**
* Implementation of LanguageVersionHandler for the C++ Language.
*/
public class CppHandler extends AbstractLanguageVersionHandler {
public RuleViolationFactory getRuleViolationFactory() {
throw new UnsupportedOperationException("getRuleViolationFactory() is not supported for C++");
}
public Parser getParser(ParserOptions parserOptions) {
return new CppParser(parserOptions);
}
}

View File

@ -0,0 +1,18 @@
package net.sourceforge.pmd.lang.cpp;
import net.sourceforge.pmd.lang.BaseLanguageModule;
/**
* Created by christoferdutz on 20.09.14.
*/
public class CppLanguageModule extends BaseLanguageModule {
public static final String NAME = "C++";
public static final String TERSE_NAME = "cpp";
public CppLanguageModule() {
super(NAME, null, TERSE_NAME, null, "h", "c", "cpp", "cxx", "cc", "C");
addVersion("", new CppHandler(), true);
}
}

View File

@ -0,0 +1,42 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.cpp;
import java.io.Reader;
import java.util.Map;
import net.sourceforge.pmd.lang.AbstractParser;
import net.sourceforge.pmd.lang.ParserOptions;
import net.sourceforge.pmd.lang.TokenManager;
import net.sourceforge.pmd.lang.ast.AbstractTokenManager;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.ast.ParseException;
/**
* Adapter for the C++ Parser.
*/
public class CppParser extends AbstractParser {
public CppParser(ParserOptions parserOptions) {
super(parserOptions);
}
@Override
public TokenManager createTokenManager(Reader source) {
return new CppTokenManager(source);
}
public boolean canParse() {
return false;
}
public Node parse(String fileName, Reader source) throws ParseException {
AbstractTokenManager.setFileName(fileName);
throw new UnsupportedOperationException("parse(Reader) is not supported for C++");
}
public Map<Integer, String> getSuppressMap() {
throw new UnsupportedOperationException("getSuppressMap() is not supported for C++");
}
}

View File

@ -0,0 +1,29 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.cpp;
import java.io.Reader;
import net.sourceforge.pmd.lang.TokenManager;
import net.sourceforge.pmd.lang.ast.SimpleCharStream;
import net.sourceforge.pmd.lang.cpp.ast.CppParserTokenManager;
/**
* C++ Token Manager implementation.
*/
public class CppTokenManager implements TokenManager {
private final CppParserTokenManager tokenManager;
public CppTokenManager(Reader source) {
tokenManager = new CppParserTokenManager(new SimpleCharStream(new ContinuationReader(source)));
}
public Object getNextToken() {
return tokenManager.getNextToken();
}
public void setFileName(String fileName) {
tokenManager.setFileName(fileName);
}
}

View File

@ -0,0 +1 @@
net.sourceforge.pmd.lang.cpp.CppLanguageModule

View File

@ -0,0 +1,52 @@
package net.sourceforge.pmd.lang.cpp;
import static org.junit.Assert.assertEquals;
import java.io.IOException;
import java.io.StringReader;
import org.junit.Test;
public class ContinuationReaderTest {
@Test
public void testHappyPath() throws IOException {
assertEquals("empty", "", filter(""));
assertEquals("anything", "anything", filter("anything"));
assertEquals("partial: BS", "\\", filter("\\"));
assertEquals("partial: BS LF", "\\\r", filter("\\\r"));
assertEquals("full: BS CR", "", filter("\\\n"));
assertEquals("full: BS LF CR", "", filter("\\\r\n"));
assertEquals("partial: BS: prefix", "prefix\\", filter("prefix\\"));
assertEquals("partial: BS LF: prefix", "prefix\\\r", filter("prefix\\\r"));
assertEquals("full: BS CR: prefix", "prefix", filter("prefix\\\n"));
assertEquals("full: BS LF CR: prefix", "prefix", filter("prefix\\\r\n"));
assertEquals("partial: BS: suffix", "\\suffix", filter("\\suffix"));
assertEquals("partial: BS LF: suffix", "\\\rsuffix", filter("\\\rsuffix"));
assertEquals("full: BS CR: suffix", "suffix", filter("\\\nsuffix"));
assertEquals("full: BS LF CR: suffix", "suffix", filter("\\\r\nsuffix"));
assertEquals("partial: BS: prefix, suffix", "prefix\\suffix", filter("prefix\\suffix"));
assertEquals("partial: BS LF: prefix, suffix", "prefix\\\rsuffix", filter("prefix\\\rsuffix"));
assertEquals("full: BS CR: prefix, suffix", "prefixsuffix", filter("prefix\\\nsuffix"));
assertEquals("full: BS LF CR: prefix, suffix", "prefixsuffix", filter("prefix\\\r\nsuffix"));
assertEquals("complex mixed", "abc", filter("a\\\r\nb\\\n\\\n\\\r\nc"));
}
private static String filter(String s) throws IOException {
ContinuationReader reader = new ContinuationReader(new StringReader(s));
try {
StringBuilder buf = new StringBuilder();
int c;
while ((c = reader.read()) >= 0) {
buf.append((char) c);
}
return buf.toString();
} finally {
reader.close();
}
}
}