forked from phoedos/pmd
Added Scala AST Parser
This commit is contained in:
parent
1a5486dc30
commit
0f7d5f1ec0
@ -95,7 +95,7 @@ public class BinaryDistributionIT {
|
||||
ExecutionResult result;
|
||||
|
||||
result = PMDExecutor.runPMD(tempDir, "-h");
|
||||
result.assertExecutionResult(0, "apex, ecmascript, java, jsp, plsql, pom, vf, vm, wsdl, xml, xsl");
|
||||
result.assertExecutionResult(0, "apex, ecmascript, java, jsp, plsql, pom, scala, vf, vm, wsdl, xml, xsl");
|
||||
|
||||
result = PMDExecutor.runPMDRules(tempDir, srcDir, "src/test/resources/rulesets/sample-ruleset.xml");
|
||||
result.assertExecutionResult(4, "JumbledIncrementer.java:8:");
|
||||
|
@ -1,116 +1,79 @@
|
||||
<?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-scala</artifactId>
|
||||
<name>PMD Scala</name>
|
||||
<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-scala</artifactId>
|
||||
<name>PMD Scala</name>
|
||||
|
||||
<parent>
|
||||
<groupId>net.sourceforge.pmd</groupId>
|
||||
<artifactId>pmd</artifactId>
|
||||
<version>6.18.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<parent>
|
||||
<groupId>net.sourceforge.pmd</groupId>
|
||||
<artifactId>pmd</artifactId>
|
||||
<version>6.18.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<scala.version>2.12.4</scala.version>
|
||||
</properties>
|
||||
<properties>
|
||||
<scalameta.version>4.2.0</scalameta.version>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>net.alchim31.maven</groupId>
|
||||
<artifactId>scala-maven-plugin</artifactId>
|
||||
<version>3.3.1</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<configuration>
|
||||
<useDefaultDelimiters>false</useDefaultDelimiters>
|
||||
<delimiters>
|
||||
<delimiter>${*}</delimiter>
|
||||
</delimiters>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<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-checkstyle-plugin</artifactId>
|
||||
<configuration>
|
||||
<suppressionsLocation>pmd-scala-checkstyle-suppressions.xml</suppressionsLocation>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>net.alchim31.maven</groupId>
|
||||
<artifactId>scala-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<addScalacArgs>-deprecation</addScalacArgs>
|
||||
<scalaVersion>${scala.version}</scalaVersion>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>scala-compile-first</id>
|
||||
<phase>process-resources</phase>
|
||||
<goals>
|
||||
<goal>add-source</goal>
|
||||
<goal>compile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>attach-javadocs</id>
|
||||
<goals>
|
||||
<goal>doc-jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<!-- Disabling the default javadoc plugin - we use scala-maven-plugin
|
||||
instead -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-javadocs</id>
|
||||
<phase>none</phase>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
<configuration>
|
||||
<suppressionsLocation>pmd-scala-checkstyle-suppressions.xml</suppressionsLocation>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.scalameta</groupId>
|
||||
<artifactId>scalameta_2.13</artifactId>
|
||||
<version>${scalameta.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sourceforge.pmd</groupId>
|
||||
<artifactId>pmd-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Disabling the default javadoc plugin - we use scala-maven-plugin instead -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-javadocs</id>
|
||||
<phase>none</phase>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.scala-lang</groupId>
|
||||
<artifactId>scala-library</artifactId>
|
||||
<version>${scala.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.scala-lang</groupId>
|
||||
<artifactId>scala-compiler</artifactId>
|
||||
<version>${scala.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sourceforge.pmd</groupId>
|
||||
<artifactId>pmd-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sourceforge.pmd</groupId>
|
||||
<artifactId>pmd-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sourceforge.pmd</groupId>
|
||||
<artifactId>pmd-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
@ -4,10 +4,8 @@
|
||||
|
||||
package net.sourceforge.pmd.cpd;
|
||||
|
||||
import org.sonar.plugins.scala.cpd.ScalaTokenizer;
|
||||
|
||||
/**
|
||||
* Language implementation for Scala
|
||||
* Language implementation for Scala.
|
||||
*/
|
||||
public class ScalaLanguage extends AbstractLanguage {
|
||||
|
||||
|
@ -0,0 +1,119 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.cpd;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import net.sourceforge.pmd.lang.LanguageRegistry;
|
||||
import net.sourceforge.pmd.lang.LanguageVersion;
|
||||
import net.sourceforge.pmd.lang.scala.ScalaLanguageHandler;
|
||||
import net.sourceforge.pmd.lang.scala.ScalaLanguageModule;
|
||||
|
||||
import scala.collection.JavaConverters;
|
||||
import scala.meta.Dialect;
|
||||
import scala.meta.inputs.Input;
|
||||
import scala.meta.internal.tokenizers.ScalametaTokenizer;
|
||||
|
||||
/**
|
||||
* Scala Tokenizer class. Uses the Scala Meta Tokenizer.
|
||||
*/
|
||||
public class ScalaTokenizer implements Tokenizer {
|
||||
|
||||
/**
|
||||
* Denotes the version of the scala dialect to use. Based on the values in
|
||||
* {@linkplain ScalaLanguageModule#getVersions()}
|
||||
*/
|
||||
public static final String SCALA_VERSION_PROPERTY = "scala_version";
|
||||
private final Dialect dialect;
|
||||
|
||||
/**
|
||||
* Create the Tokenizer using properties from the system environment.
|
||||
*/
|
||||
public ScalaTokenizer() {
|
||||
this(System.getProperties());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the Tokenizer given a set of properties.
|
||||
*
|
||||
* @param properties
|
||||
* the {@linkplain Properties} object to use
|
||||
*/
|
||||
public ScalaTokenizer(Properties properties) {
|
||||
String scalaVersion = properties.getProperty(SCALA_VERSION_PROPERTY);
|
||||
LanguageVersion langVer;
|
||||
if (scalaVersion == null) {
|
||||
langVer = LanguageRegistry.getLanguage(ScalaLanguageModule.NAME).getDefaultVersion();
|
||||
} else {
|
||||
langVer = LanguageRegistry.getLanguage(ScalaLanguageModule.NAME).getVersion(scalaVersion);
|
||||
}
|
||||
dialect = ((ScalaLanguageHandler) langVer.getLanguageVersionHandler()).getDialect();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tokenize(SourceCode sourceCode, Tokens tokenEntries) throws IOException {
|
||||
String filename = sourceCode.getFileName();
|
||||
// create the full code file
|
||||
String fullCode = StringUtils.join(sourceCode.getCode(), "\n");
|
||||
|
||||
// create the input file for scala
|
||||
Input.VirtualFile vf = new Input.VirtualFile(filename, fullCode);
|
||||
ScalametaTokenizer tokenizer = new ScalametaTokenizer(vf, dialect);
|
||||
|
||||
// tokenize with a filter
|
||||
scala.meta.tokens.Tokens tokens = tokenizer.tokenize();
|
||||
List<scala.meta.tokens.Token> tokenList = JavaConverters.asJava(tokens.toList());
|
||||
|
||||
ScalaTokenFilter filter = new ScalaTokenFilter(tokenList);
|
||||
|
||||
scala.meta.tokens.Token token;
|
||||
while ((token = filter.getNextToken()) != null) {
|
||||
String tokenText = token.text() != null ? token.text() : token.name();
|
||||
TokenEntry cpdToken = new TokenEntry(tokenText, filename, token.pos().startLine());
|
||||
tokenEntries.add(cpdToken);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Token Filter skips un-helpful tokens to only register important tokens
|
||||
* and patterns.
|
||||
*/
|
||||
private static class ScalaTokenFilter {
|
||||
Iterator<scala.meta.tokens.Token> tokenListIter;
|
||||
|
||||
ScalaTokenFilter(List<scala.meta.tokens.Token> tokenList) {
|
||||
this.tokenListIter = tokenList.iterator();
|
||||
}
|
||||
|
||||
scala.meta.tokens.Token getNextToken() {
|
||||
if (!tokenListIter.hasNext()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
scala.meta.tokens.Token token;
|
||||
do {
|
||||
token = tokenListIter.next();
|
||||
} while (token != null && skipToken(token) && tokenListIter.hasNext());
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
private boolean skipToken(scala.meta.tokens.Token token) {
|
||||
boolean skip = false;
|
||||
if (token.text() != null) {
|
||||
// skip any token that is whitespaces
|
||||
skip |= token instanceof scala.meta.tokens.Token.Space || token instanceof scala.meta.tokens.Token.Tab
|
||||
|| token instanceof scala.meta.tokens.Token.CR || token instanceof scala.meta.tokens.Token.LF
|
||||
|| token instanceof scala.meta.tokens.Token.FF || token instanceof scala.meta.tokens.Token.LFLF;
|
||||
}
|
||||
return skip;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.scala;
|
||||
|
||||
import java.io.Writer;
|
||||
|
||||
import net.sourceforge.pmd.lang.AbstractLanguageVersionHandler;
|
||||
import net.sourceforge.pmd.lang.ParserOptions;
|
||||
import net.sourceforge.pmd.lang.VisitorStarter;
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
import net.sourceforge.pmd.lang.rule.RuleViolationFactory;
|
||||
import net.sourceforge.pmd.lang.scala.ast.DumpFacade;
|
||||
import net.sourceforge.pmd.lang.scala.ast.ScalaNode;
|
||||
import net.sourceforge.pmd.lang.scala.rule.ScalaRuleViolationFactory;
|
||||
|
||||
import scala.meta.Dialect;
|
||||
|
||||
/**
|
||||
* The Scala Language Handler implementation.
|
||||
*/
|
||||
public class ScalaLanguageHandler extends AbstractLanguageVersionHandler {
|
||||
|
||||
private final Dialect dialect;
|
||||
|
||||
/**
|
||||
* Create the Language Handler using the given Scala Dialect.
|
||||
*
|
||||
* @param scalaDialect
|
||||
* the language version to use while parsing etc
|
||||
*/
|
||||
public ScalaLanguageHandler(Dialect scalaDialect) {
|
||||
this.dialect = scalaDialect;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Scala Dialect used in this language version choice.
|
||||
*
|
||||
* @return the Scala Dialect for this handler
|
||||
*/
|
||||
public Dialect getDialect() {
|
||||
return this.dialect;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RuleViolationFactory getRuleViolationFactory() {
|
||||
return ScalaRuleViolationFactory.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScalaParser getParser(ParserOptions parserOptions) {
|
||||
return new ScalaParser(dialect, parserOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VisitorStarter getDumpFacade(final Writer writer, final String prefix, final boolean recurse) {
|
||||
return new VisitorStarter() {
|
||||
@Override
|
||||
public void start(Node rootNode) {
|
||||
new DumpFacade().dump(writer, prefix, recurse, (ScalaNode) rootNode);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
@ -5,13 +5,11 @@
|
||||
package net.sourceforge.pmd.lang.scala;
|
||||
|
||||
import net.sourceforge.pmd.lang.BaseLanguageModule;
|
||||
import net.sourceforge.pmd.lang.scala.rule.ScalaRuleChainVisitor;
|
||||
|
||||
/**
|
||||
* Language Module for Scala
|
||||
*
|
||||
* @deprecated There is no full PMD support for Scala.
|
||||
* Language Module for Scala.
|
||||
*/
|
||||
@Deprecated
|
||||
public class ScalaLanguageModule extends BaseLanguageModule {
|
||||
|
||||
/** The name. */
|
||||
@ -23,7 +21,10 @@ public class ScalaLanguageModule extends BaseLanguageModule {
|
||||
* Create a new instance of Scala Language Module.
|
||||
*/
|
||||
public ScalaLanguageModule() {
|
||||
super(NAME, null, TERSE_NAME, null, "scala");
|
||||
addVersion("", null, true);
|
||||
super(NAME, null, TERSE_NAME, ScalaRuleChainVisitor.class, "scala");
|
||||
addVersion("2.13", new ScalaLanguageHandler(scala.meta.dialects.package$.MODULE$.Scala213()), true);
|
||||
addVersion("2.12", new ScalaLanguageHandler(scala.meta.dialects.package$.MODULE$.Scala212()), false);
|
||||
addVersion("2.11", new ScalaLanguageHandler(scala.meta.dialects.package$.MODULE$.Scala211()), false);
|
||||
addVersion("2.10", new ScalaLanguageHandler(scala.meta.dialects.package$.MODULE$.Scala210()), false);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,103 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.scala;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import net.sourceforge.pmd.lang.AbstractParser;
|
||||
import net.sourceforge.pmd.lang.ParserOptions;
|
||||
import net.sourceforge.pmd.lang.TokenManager;
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
import net.sourceforge.pmd.lang.ast.ParseException;
|
||||
import net.sourceforge.pmd.lang.scala.ast.ASTSourceNode;
|
||||
import net.sourceforge.pmd.lang.scala.ast.ScalaWrapperNode;
|
||||
|
||||
import scala.meta.Dialect;
|
||||
import scala.meta.Source;
|
||||
import scala.meta.Tree;
|
||||
import scala.meta.inputs.Input;
|
||||
import scala.meta.internal.parsers.ScalametaParser;
|
||||
|
||||
/**
|
||||
* Scala's Parser implementation. Defers parsing to the scala compiler via
|
||||
* Scalameta. This parser then wraps all of ScalaMeta's Nodes in Java versions
|
||||
* for compatibility.
|
||||
*/
|
||||
public class ScalaParser extends AbstractParser {
|
||||
private final Dialect dialect;
|
||||
|
||||
private Map<Tree, ScalaWrapperNode> nodeCache = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Create a parser using the given Scala Dialect and set of parser options.
|
||||
*
|
||||
* @param scalaDialect
|
||||
* the Scala Dialect for this parser
|
||||
* @param parserOptions
|
||||
* any additional options for this parser
|
||||
*/
|
||||
public ScalaParser(Dialect scalaDialect, ParserOptions parserOptions) {
|
||||
super(parserOptions);
|
||||
this.dialect = scalaDialect;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canParse() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node parse(String fileName, Reader source) throws ParseException {
|
||||
nodeCache.clear();
|
||||
Input.VirtualFile virtualFile;
|
||||
try {
|
||||
String sourceString = IOUtils.toString(source);
|
||||
virtualFile = new Input.VirtualFile(fileName, sourceString);
|
||||
} catch (IOException e) {
|
||||
throw new ParseException(e);
|
||||
}
|
||||
Source src = new ScalametaParser(virtualFile, dialect).parseSource();
|
||||
ASTSourceNode srcNode = new ASTSourceNode(this, src);
|
||||
nodeCache.put(src, srcNode);
|
||||
return srcNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a wrapper around the given node so that we can interact with PMD
|
||||
* systems using the underlying scala node.
|
||||
*
|
||||
* @param scalaNode
|
||||
* a node from Scala's parsing
|
||||
* @return A Java-wrapped version of the given node, using a cache if this
|
||||
* has been previously wrapped, or null, if the given node is null
|
||||
*/
|
||||
public ScalaWrapperNode wrapNode(Tree scalaNode) {
|
||||
if (scalaNode == null) {
|
||||
return null;
|
||||
}
|
||||
ScalaWrapperNode node = nodeCache.get(scalaNode);
|
||||
if (node == null) {
|
||||
node = new ScalaWrapperNode(this, scalaNode);
|
||||
nodeCache.put(scalaNode, node);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Integer, String> getSuppressMap() {
|
||||
return new HashMap<>(); // FIXME;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TokenManager createTokenManager(Reader source) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.scala.ast;
|
||||
|
||||
import net.sourceforge.pmd.lang.ast.RootNode;
|
||||
import net.sourceforge.pmd.lang.scala.ScalaParser;
|
||||
|
||||
import scala.meta.Source;
|
||||
|
||||
/**
|
||||
* The root node for a Scala AST.
|
||||
*/
|
||||
public class ASTSourceNode extends ScalaWrapperNode implements RootNode {
|
||||
|
||||
/**
|
||||
* Create a new root node wrapper for the Scala root AST node.
|
||||
*
|
||||
* @param scalaParser
|
||||
* the ScalaParser used to generate the node
|
||||
* @param scalaNode
|
||||
* the scalaNode node to wrap
|
||||
*/
|
||||
public ASTSourceNode(ScalaParser scalaParser, Source scalaNode) {
|
||||
super(scalaParser, scalaNode);
|
||||
}
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.scala.ast;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.Iterator;
|
||||
|
||||
import net.sourceforge.pmd.lang.ast.xpath.Attribute;
|
||||
|
||||
/**
|
||||
* A Dump Facade for Scala for testing purposes.
|
||||
*/
|
||||
public class DumpFacade extends ScalaParserVisitorAdapter {
|
||||
private PrintWriter writer;
|
||||
private boolean recurse;
|
||||
|
||||
/**
|
||||
* Write the nodes of the tree to the given writer recursively.
|
||||
*
|
||||
* @param outWriter
|
||||
* the writer to write the tree data to
|
||||
* @param prefix
|
||||
* a string prefix to use before each line in the writer
|
||||
* @param shouldRecurse
|
||||
* should this recurse below the root node?
|
||||
* @param node
|
||||
* the node to start with. Not necessarily a tree root.
|
||||
*/
|
||||
public void dump(Writer outWriter, String prefix, boolean shouldRecurse, ScalaNode node) {
|
||||
this.writer = outWriter instanceof PrintWriter ? (PrintWriter) outWriter : new PrintWriter(outWriter);
|
||||
this.recurse = shouldRecurse;
|
||||
this.visit(node, prefix);
|
||||
this.writer.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(ScalaNode node, Object data) {
|
||||
dump(node, (String) data);
|
||||
if (recurse) {
|
||||
return super.visit(node, data + " ");
|
||||
} else {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
private void dump(ScalaNode node, String prefix) {
|
||||
writer.print(prefix);
|
||||
writer.print(node.getXPathNodeName());
|
||||
|
||||
String image = node.getImage();
|
||||
|
||||
String attrs = null;
|
||||
Iterator<Attribute> attributeIter = node.getXPathAttributesIterator();
|
||||
if (attributeIter.hasNext()) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
while (attributeIter.hasNext()) {
|
||||
Attribute attr = attributeIter.next();
|
||||
sb.append(attr.getName()).append("=").append(attr.getStringValue()).append(",");
|
||||
}
|
||||
attrs = sb.deleteCharAt(sb.length()).toString();
|
||||
}
|
||||
|
||||
if (image != null) {
|
||||
writer.print(":" + image);
|
||||
}
|
||||
|
||||
if (attrs != null) {
|
||||
writer.print("[");
|
||||
writer.print(attrs);
|
||||
writer.print("]");
|
||||
}
|
||||
|
||||
writer.println();
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.scala.ast;
|
||||
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
|
||||
import scala.meta.Tree;
|
||||
|
||||
/**
|
||||
* A Base interface of a Scala Node. Defines several required methods of all
|
||||
* nodes.
|
||||
*/
|
||||
public interface ScalaNode extends Node {
|
||||
/**
|
||||
* Accept a visitor and traverse this node.
|
||||
*
|
||||
* @param visitor
|
||||
* the visitor to visit this node with
|
||||
* @param data
|
||||
* context-specific data to pass along
|
||||
* @return context-specific data for this Visitor pattern
|
||||
*/
|
||||
Object accept(ScalaParserVisitor visitor, Object data);
|
||||
|
||||
/**
|
||||
* Accept the visitor against all children of this node if there are any and
|
||||
* return.
|
||||
*
|
||||
* @param visitor
|
||||
* the visitor to visit this node's children with
|
||||
* @param data
|
||||
* context-specific data to pass along
|
||||
* @return context-specific data for this Visitor pattern
|
||||
*/
|
||||
Object childrenAccept(ScalaParserVisitor visitor, Object data);
|
||||
|
||||
/**
|
||||
* Get the underlying Scala Node.
|
||||
*
|
||||
* @return the Scala Node for this node
|
||||
*/
|
||||
Tree getNode();
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.scala.ast;
|
||||
|
||||
/**
|
||||
* A Visitor Pattern Interface for the Scala AST.
|
||||
*/
|
||||
public interface ScalaParserVisitor {
|
||||
/**
|
||||
* Visit the Source Node (the root node of the tree).
|
||||
*
|
||||
* @param node
|
||||
* the root node of the tree
|
||||
* @param data
|
||||
* context-specific data
|
||||
* @return context-specific data
|
||||
*/
|
||||
Object visit(ASTSourceNode node, Object data);
|
||||
|
||||
/**
|
||||
* Visit an arbitrary Scala Node (any node in the tree).
|
||||
*
|
||||
* @param node
|
||||
* the node of the tree
|
||||
* @param data
|
||||
* context-specific data
|
||||
* @return context-specific data
|
||||
*/
|
||||
Object visit(ScalaNode node, Object data);
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.scala.ast;
|
||||
|
||||
/**
|
||||
* An Adapter for the Scala Parser that implements the Visitor Pattern.
|
||||
*/
|
||||
public class ScalaParserVisitorAdapter implements ScalaParserVisitor {
|
||||
@Override
|
||||
public Object visit(ScalaNode node, Object data) {
|
||||
return node.childrenAccept(this, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(ASTSourceNode node, Object data) {
|
||||
return visit((ScalaNode) node, data);
|
||||
}
|
||||
}
|
@ -0,0 +1,182 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.scala.ast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import net.sourceforge.pmd.lang.ast.AbstractNode;
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
import net.sourceforge.pmd.lang.ast.xpath.Attribute;
|
||||
import net.sourceforge.pmd.lang.scala.ScalaParser;
|
||||
import net.sourceforge.pmd.util.CompoundIterator;
|
||||
|
||||
import scala.meta.Tree;
|
||||
import scala.meta.inputs.Position;
|
||||
|
||||
/**
|
||||
* The Java-wrapper for Scala Nodes to allow interoperability with PMD.
|
||||
*/
|
||||
public class ScalaWrapperNode extends AbstractNode implements ScalaNode {
|
||||
private Tree node;
|
||||
private ScalaParser parser;
|
||||
|
||||
/**
|
||||
* Create a new Java Wrapper around a Scala node.
|
||||
*
|
||||
* @param scalaParser
|
||||
* the ScalaParser used to generate the node
|
||||
* @param scalaNode
|
||||
* the scalaNode node to wrap
|
||||
*/
|
||||
public ScalaWrapperNode(ScalaParser scalaParser, Tree scalaNode) {
|
||||
super(0);
|
||||
this.parser = scalaParser;
|
||||
this.node = scalaNode;
|
||||
Position pos = node.pos();
|
||||
beginLine = pos.startLine() + 1;
|
||||
endLine = pos.endLine();
|
||||
beginColumn = pos.startColumn();
|
||||
endColumn = pos.endColumn() + 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tree getNode() {
|
||||
return node;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object accept(ScalaParserVisitor visitor, Object data) {
|
||||
return visitor.visit(this, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object childrenAccept(ScalaParserVisitor visitor, Object data) {
|
||||
int numChildren = jjtGetNumChildren();
|
||||
for (int i = 0; i < numChildren; ++i) {
|
||||
jjtGetChild(i).accept(visitor, data);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getXPathNodeName() {
|
||||
return "AST" + node.productPrefix().replace(".", "") + "Node";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jjtClose() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jjtSetParent(Node parent) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScalaWrapperNode jjtGetParent() {
|
||||
if (node.parent().isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return parser.wrapNode(node.parent().get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jjtAddChild(Node child, int index) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jjtSetChildIndex(int index) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int jjtGetChildIndex() {
|
||||
int idx = node.parent().get().children().indexOf(node);
|
||||
if (idx == -1) {
|
||||
throw new IllegalStateException("This node is not a child of its parent: " + node);
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScalaWrapperNode jjtGetChild(int index) {
|
||||
return parser.wrapNode(node.children().apply(index));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int jjtGetNumChildren() {
|
||||
return node.children().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int jjtGetId() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getImage() {
|
||||
String image = null;
|
||||
if (node instanceof scala.meta.Lit) {
|
||||
image = String.valueOf(((scala.meta.Lit) node).value());
|
||||
} else if (node instanceof scala.meta.Name) {
|
||||
image = ((scala.meta.Name) node).value().toString();
|
||||
} else if (node instanceof scala.meta.Type.Name) {
|
||||
image = ((scala.meta.Type.Name) node).value();
|
||||
} else if (node instanceof scala.meta.Term.Name) {
|
||||
image = ((scala.meta.Term.Name) node).value();
|
||||
} else if (node instanceof scala.meta.Type.Var.Name) {
|
||||
image = ((scala.meta.Type.Var.Name) node).value();
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setImage(String image) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasImageEqualTo(String image) {
|
||||
return Objects.equals(image, getImage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeChildAtIndex(int childIndex) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Attribute> getXPathAttributesIterator() {
|
||||
List<Iterator<Attribute>> iterators = new ArrayList<>();
|
||||
|
||||
// Possible things we would want to expose to the XPath AST
|
||||
//
|
||||
// JavaConverters.asJava(node.productElementNames()).forEachRemaining(System.out::print);
|
||||
// JavaConverters.asJava(node.productFields()).forEach(System.out::print);
|
||||
// JavaConverters.asJava(node.productIterator()).forEachRemaining(System.out::print);
|
||||
|
||||
String image = getImage();
|
||||
if (image != null) {
|
||||
iterators.add(Collections.singletonList(new Attribute(this, "Image", image)).iterator());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Iterator<Attribute>[] it = new Iterator[iterators.size()];
|
||||
|
||||
return new CompoundIterator<>(iterators.toArray(it));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.scala.rule;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import net.sourceforge.pmd.RuleContext;
|
||||
import net.sourceforge.pmd.lang.LanguageRegistry;
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
import net.sourceforge.pmd.lang.rule.AbstractRule;
|
||||
import net.sourceforge.pmd.lang.scala.ScalaLanguageModule;
|
||||
import net.sourceforge.pmd.lang.scala.ast.ASTSourceNode;
|
||||
import net.sourceforge.pmd.lang.scala.ast.ScalaNode;
|
||||
import net.sourceforge.pmd.lang.scala.ast.ScalaParserVisitor;
|
||||
|
||||
/**
|
||||
* The default base implementation of a PMD Rule for Scala. Uses the Visitor
|
||||
* Pattern to traverse the AST.
|
||||
*/
|
||||
public class ScalaRule extends AbstractRule implements ScalaParserVisitor {
|
||||
|
||||
/**
|
||||
* Create a new Scala Rule.
|
||||
*/
|
||||
public ScalaRule() {
|
||||
super.setLanguage(LanguageRegistry.getLanguage(ScalaLanguageModule.NAME));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(List<? extends Node> nodes, RuleContext ctx) {
|
||||
for (Node node : nodes) {
|
||||
if (node instanceof ASTSourceNode) {
|
||||
visit((ASTSourceNode) node, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(ASTSourceNode node, Object data) {
|
||||
return visit((ScalaNode) node, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(ScalaNode node, Object data) {
|
||||
return node.childrenAccept(this, data);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.scala.rule;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import net.sourceforge.pmd.Rule;
|
||||
import net.sourceforge.pmd.RuleContext;
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
import net.sourceforge.pmd.lang.rule.AbstractRuleChainVisitor;
|
||||
import net.sourceforge.pmd.lang.rule.XPathRule;
|
||||
import net.sourceforge.pmd.lang.scala.ast.ASTSourceNode;
|
||||
import net.sourceforge.pmd.lang.scala.ast.ScalaNode;
|
||||
import net.sourceforge.pmd.lang.scala.ast.ScalaParserVisitor;
|
||||
import net.sourceforge.pmd.lang.scala.ast.ScalaParserVisitorAdapter;
|
||||
import net.sourceforge.pmd.lang.scala.ast.ScalaWrapperNode;
|
||||
|
||||
/**
|
||||
* A Rule Chain visitor for Scala.
|
||||
*/
|
||||
public class ScalaRuleChainVisitor extends AbstractRuleChainVisitor {
|
||||
|
||||
@Override
|
||||
protected void visit(Rule rule, Node node, RuleContext ctx) {
|
||||
// Rule better either be a JavaParserVisitor, or a XPathRule
|
||||
if (rule instanceof XPathRule) {
|
||||
((XPathRule) rule).evaluate(node, ctx);
|
||||
} else {
|
||||
((ScalaWrapperNode) node).accept((ScalaParserVisitorAdapter) rule, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void indexNodes(List<Node> nodes, RuleContext ctx) {
|
||||
ScalaParserVisitor visitor = new ScalaParserVisitorAdapter() {
|
||||
@Override
|
||||
public Object visit(ScalaNode node, Object data) {
|
||||
indexNode(node);
|
||||
return super.visit(node, data);
|
||||
}
|
||||
};
|
||||
for (final Node node : nodes) {
|
||||
visitor.visit((ASTSourceNode) node, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.scala.rule;
|
||||
|
||||
import net.sourceforge.pmd.Rule;
|
||||
import net.sourceforge.pmd.RuleContext;
|
||||
import net.sourceforge.pmd.RuleViolation;
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
import net.sourceforge.pmd.lang.rule.AbstractRuleViolationFactory;
|
||||
import net.sourceforge.pmd.lang.rule.ParametricRuleViolation;
|
||||
import net.sourceforge.pmd.lang.rule.RuleViolationFactory;
|
||||
|
||||
/**
|
||||
* A RuleViolationFactory for Scala.
|
||||
*/
|
||||
public class ScalaRuleViolationFactory extends AbstractRuleViolationFactory {
|
||||
/**
|
||||
* The shared singleton of this RuleViolationFactory.
|
||||
*/
|
||||
public static final RuleViolationFactory INSTANCE = new ScalaRuleViolationFactory();
|
||||
|
||||
@Override
|
||||
protected RuleViolation createRuleViolation(Rule rule, RuleContext ruleContext, Node node, String message) {
|
||||
return new ParametricRuleViolation<Node>(rule, ruleContext, node, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RuleViolation createRuleViolation(Rule rule, RuleContext ruleContext, Node node, String message,
|
||||
int beginLine, int endLine) {
|
||||
ParametricRuleViolation<Node> rv = new ParametricRuleViolation<>(rule, ruleContext, node, message);
|
||||
rv.setLines(beginLine, endLine);
|
||||
return rv;
|
||||
}
|
||||
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
/*
|
||||
* Sonar Scala Plugin
|
||||
* Copyright (C) 2011 - 2014 All contributors
|
||||
* dev@sonar.codehaus.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
|
||||
*/
|
||||
|
||||
package org.sonar.plugins.scala.cpd;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.sonar.plugins.scala.compiler.Lexer;
|
||||
import org.sonar.plugins.scala.compiler.Token;
|
||||
|
||||
import net.sourceforge.pmd.cpd.SourceCode;
|
||||
import net.sourceforge.pmd.cpd.TokenEntry;
|
||||
import net.sourceforge.pmd.cpd.Tokenizer;
|
||||
import net.sourceforge.pmd.cpd.Tokens;
|
||||
import net.sourceforge.pmd.lang.ast.TokenMgrError;
|
||||
|
||||
/**
|
||||
* Scala tokenizer for PMD CPD.
|
||||
*
|
||||
* @since 0.1
|
||||
*/
|
||||
public final class ScalaTokenizer implements Tokenizer {
|
||||
|
||||
@Override
|
||||
public void tokenize(SourceCode source, Tokens cpdTokens) {
|
||||
String filename = source.getFileName();
|
||||
|
||||
try {
|
||||
Lexer lexer = new Lexer();
|
||||
List<Token> tokens = lexer.getTokensOfFile(filename);
|
||||
for (Token token : tokens) {
|
||||
String tokenVal = token.tokenVal() != null ? token.tokenVal() : Integer.toString(token.tokenType());
|
||||
|
||||
TokenEntry cpdToken = new TokenEntry(tokenVal, filename, token.line());
|
||||
cpdTokens.add(cpdToken);
|
||||
}
|
||||
cpdTokens.add(TokenEntry.getEOF());
|
||||
} catch (RuntimeException e) {
|
||||
e.printStackTrace();
|
||||
// Wrap exceptions of the Scala tokenizer in a TokenMgrError, so
|
||||
// they are correctly handled
|
||||
// when CPD is executed with the '--skipLexicalErrors' command line
|
||||
// option
|
||||
throw new TokenMgrError(
|
||||
"Lexical error in file " + filename + ". The scala tokenizer exited with error: " + e.getMessage(),
|
||||
TokenMgrError.LEXICAL_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,117 +0,0 @@
|
||||
/*
|
||||
* Sonar Scala Plugin
|
||||
* Copyright (C) 2011 - 2014 All contributors
|
||||
* dev@sonar.codehaus.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
|
||||
*/
|
||||
|
||||
package org.sonar.plugins.scala.language;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.sonar.plugins.scala.util.StringUtils;
|
||||
|
||||
/**
|
||||
* This class implements a Scala comment and the computation of several base
|
||||
* metrics for a comment.
|
||||
*
|
||||
* @author Felix Müller
|
||||
* @since 0.1
|
||||
*/
|
||||
public class Comment {
|
||||
|
||||
private final CommentType type;
|
||||
private final List<String> lines;
|
||||
|
||||
public Comment(String content, CommentType type) throws IOException {
|
||||
lines = StringUtils.convertStringToListOfLines(content);
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public int getNumberOfLines() {
|
||||
return lines.size() - getNumberOfBlankLines() - getNumberOfCommentedOutLinesOfCode();
|
||||
}
|
||||
|
||||
public int getNumberOfBlankLines() {
|
||||
int numberOfBlankLines = 0;
|
||||
for (String comment : lines) {
|
||||
boolean isBlank = true;
|
||||
|
||||
for (int i = 0; isBlank && i < comment.length(); i++) {
|
||||
char character = comment.charAt(i);
|
||||
if (!Character.isWhitespace(character) && character != '*' && character != '/') {
|
||||
isBlank = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (isBlank) {
|
||||
numberOfBlankLines++;
|
||||
}
|
||||
}
|
||||
return numberOfBlankLines;
|
||||
}
|
||||
|
||||
public int getNumberOfCommentedOutLinesOfCode() {
|
||||
if (isDocComment()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int numberOfCommentedOutLinesOfCode = 0;
|
||||
for (String line : lines) {
|
||||
String strippedLine = org.apache.commons.lang3.StringUtils.strip(line, " /*");
|
||||
if (CodeDetector.hasDetectedCode(strippedLine)) {
|
||||
numberOfCommentedOutLinesOfCode++;
|
||||
}
|
||||
}
|
||||
return numberOfCommentedOutLinesOfCode;
|
||||
}
|
||||
|
||||
public boolean isDocComment() {
|
||||
return type == CommentType.DOC;
|
||||
}
|
||||
|
||||
public boolean isHeaderComment() {
|
||||
return type == CommentType.HEADER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return new HashCodeBuilder().append(type).append(lines).toHashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof Comment)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Comment other = (Comment) obj;
|
||||
return new EqualsBuilder().append(type, other.type).append(lines, other.lines).isEquals();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final String firstLine = lines.isEmpty() ? "" : lines.get(0);
|
||||
final String lastLine = lines.isEmpty() ? "" : lines.get(lines.size() - 1);
|
||||
return new ToStringBuilder(this).append("type", type).append("firstLine", firstLine)
|
||||
.append("lastLine", lastLine).append("numberOfLines", getNumberOfLines())
|
||||
.append("numberOfCommentedOutLinesOfCode", getNumberOfCommentedOutLinesOfCode()).toString();
|
||||
}
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Sonar Scala Plugin
|
||||
* Copyright (C) 2011 - 2014 All contributors
|
||||
* dev@sonar.codehaus.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
|
||||
*/
|
||||
|
||||
package org.sonar.plugins.scala.language;
|
||||
|
||||
/**
|
||||
* This enum is a helper to distinguish between the different types of comments
|
||||
* in Sonar.
|
||||
*
|
||||
* @author Felix Müller
|
||||
* @since 0.1
|
||||
*/
|
||||
public enum CommentType {
|
||||
|
||||
NORMAL, DOC, HEADER;
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Sonar Scala Plugin
|
||||
* Copyright (C) 2011 - 2014 All contributors
|
||||
* dev@sonar.codehaus.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
|
||||
*/
|
||||
|
||||
package org.sonar.plugins.scala.util;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public final class StringUtils {
|
||||
private StringUtils() {
|
||||
// to prevent instantiation
|
||||
}
|
||||
|
||||
public static List<String> convertStringToListOfLines(String string) throws IOException {
|
||||
final List<String> lines = new ArrayList<>();
|
||||
try (BufferedReader reader = new BufferedReader(new StringReader(string))) {
|
||||
String line = null;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
lines.add(line);
|
||||
}
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<ruleset name="Best Practices"
|
||||
xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd">
|
||||
|
||||
<description>
|
||||
Rules which enforce generally accepted best practices.
|
||||
</description>
|
||||
</ruleset>
|
@ -0,0 +1,18 @@
|
||||
#
|
||||
# BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
#
|
||||
|
||||
rulesets.filenames=
|
||||
|
||||
#
|
||||
# categories without rules
|
||||
#
|
||||
# category/scala/bestpractices.xml
|
||||
# category/scala/codestyle.xml
|
||||
# category/scala/design.xml
|
||||
# category/scala/documentation.xml
|
||||
# category/scala/errorprone.xml
|
||||
# category/scala/multithreading.xml
|
||||
# category/scala/performance.xml
|
||||
# category/scala/security.xml
|
||||
|
11
pmd-scala/src/main/resources/category/scala/codestyle.xml
Normal file
11
pmd-scala/src/main/resources/category/scala/codestyle.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<ruleset name="Code Style"
|
||||
xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd">
|
||||
|
||||
<description>
|
||||
Rules which enforce a specific coding style.
|
||||
</description>
|
||||
</ruleset>
|
11
pmd-scala/src/main/resources/category/scala/design.xml
Normal file
11
pmd-scala/src/main/resources/category/scala/design.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<ruleset name="Design"
|
||||
xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd">
|
||||
|
||||
<description>
|
||||
Rules that help you discover design issues.
|
||||
</description>
|
||||
</ruleset>
|
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<ruleset name="Documentation"
|
||||
xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd">
|
||||
|
||||
<description>
|
||||
Rules that are related to code documentation.
|
||||
</description>
|
||||
</ruleset>
|
13
pmd-scala/src/main/resources/category/scala/errorprone.xml
Normal file
13
pmd-scala/src/main/resources/category/scala/errorprone.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<ruleset name="Error Prone"
|
||||
xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd">
|
||||
|
||||
<description>
|
||||
Rules to detect constructs that are either broken, extremely confusing or prone to runtime errors.
|
||||
</description>
|
||||
|
||||
|
||||
</ruleset>
|
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<ruleset name="Multithreading"
|
||||
xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd">
|
||||
|
||||
<description>
|
||||
Rules that flag issues when dealing with multiple threads of execution.
|
||||
</description>
|
||||
</ruleset>
|
11
pmd-scala/src/main/resources/category/scala/performance.xml
Normal file
11
pmd-scala/src/main/resources/category/scala/performance.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<ruleset name="Performance"
|
||||
xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd">
|
||||
|
||||
<description>
|
||||
Rules that flag suboptimal code.
|
||||
</description>
|
||||
</ruleset>
|
11
pmd-scala/src/main/resources/category/scala/security.xml
Normal file
11
pmd-scala/src/main/resources/category/scala/security.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<ruleset name="Security"
|
||||
xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd">
|
||||
|
||||
<description>
|
||||
Rules that flag potential security flaws.
|
||||
</description>
|
||||
</ruleset>
|
@ -0,0 +1,18 @@
|
||||
#
|
||||
# BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
#
|
||||
|
||||
rulesets.filenames=
|
||||
|
||||
#
|
||||
# categories without rules
|
||||
#
|
||||
# category/scala/bestpractices.xml
|
||||
# category/scala/codestyle.xml
|
||||
# category/scala/design.xml
|
||||
# category/scala/documentation.xml
|
||||
# category/scala/errorprone.xml
|
||||
# category/scala/multithreading.xml
|
||||
# category/scala/performance.xml
|
||||
# category/scala/security.xml
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user