Move cpp into own sub-module
This commit is contained in:
1591
pmd-cpp/etc/grammar/cpp.jj
Normal file
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
185
pmd-cpp/pom.xml
Normal 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>
|
45
pmd-cpp/src/main/ant/alljavacc.xml
Normal file
45
pmd-cpp/src/main/ant/alljavacc.xml
Normal 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>
|
@ -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");
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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++");
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
net.sourceforge.pmd.lang.cpp.CppLanguageModule
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user