Page MenuHomePhabricator

D14632.id35533.diff
No OneTemporary

D14632.id35533.diff

diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -53,6 +53,8 @@
'ArcanistCapabilityNotSupportedException' => 'workflow/exception/ArcanistCapabilityNotSupportedException.php',
'ArcanistCastSpacingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistCastSpacingXHPASTLinterRule.php',
'ArcanistCastSpacingXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistCastSpacingXHPASTLinterRuleTestCase.php',
+ 'ArcanistCheckstyleLinter' => 'lint/linter/ArcanistCheckstyleLinter.php',
+ 'ArcanistCheckstyleLinterTestCase' => 'lint/linter/__tests__/ArcanistCheckstyleLinterTestCase.php',
'ArcanistCheckstyleXMLLintRenderer' => 'lint/renderer/ArcanistCheckstyleXMLLintRenderer.php',
'ArcanistChmodLinter' => 'lint/linter/ArcanistChmodLinter.php',
'ArcanistChmodLinterTestCase' => 'lint/linter/__tests__/ArcanistChmodLinterTestCase.php',
@@ -264,6 +266,7 @@
'ArcanistPHPOpenTagXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistPHPOpenTagXHPASTLinterRuleTestCase.php',
'ArcanistPHPShortTagXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistPHPShortTagXHPASTLinterRule.php',
'ArcanistPHPShortTagXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistPHPShortTagXHPASTLinterRuleTestCase.php',
+ 'ArcanistPMDLinter' => 'lint/linter/ArcanistPMDLinter.php',
'ArcanistParentMemberReferenceXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistParentMemberReferenceXHPASTLinterRule.php',
'ArcanistParentMemberReferenceXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistParentMemberReferenceXHPASTLinterRuleTestCase.php',
'ArcanistParenthesesSpacingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistParenthesesSpacingXHPASTLinterRule.php',
@@ -451,6 +454,8 @@
'ArcanistCapabilityNotSupportedException' => 'Exception',
'ArcanistCastSpacingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistCastSpacingXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
+ 'ArcanistCheckstyleLinter' => 'ArcanistExternalLinter',
+ 'ArcanistCheckstyleLinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistCheckstyleXMLLintRenderer' => 'ArcanistLintRenderer',
'ArcanistChmodLinter' => 'ArcanistLinter',
'ArcanistChmodLinterTestCase' => 'ArcanistLinterTestCase',
@@ -662,6 +667,7 @@
'ArcanistPHPOpenTagXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistPHPShortTagXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistPHPShortTagXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
+ 'ArcanistPMDLinter' => 'ArcanistExternalLinter',
'ArcanistParentMemberReferenceXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistParentMemberReferenceXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistParenthesesSpacingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
diff --git a/src/lint/linter/ArcanistCheckstyleLinter.php b/src/lint/linter/ArcanistCheckstyleLinter.php
new file mode 100644
--- /dev/null
+++ b/src/lint/linter/ArcanistCheckstyleLinter.php
@@ -0,0 +1,177 @@
+<?php
+
+/**
+ * This linter invokes checkstyle for verifying java coding standards.
+ * The checkstyle report is given over stdout as a simple XML document
+ * which maps fairly easily to ArcanistLintMessage.
+ */
+class ArcanistCheckstyleLinter extends ArcanistExternalLinter {
+
+ private $simplifySourceClassname = false;
+
+ public function getInfoName() {
+ return 'Java checkstyle linter';
+ }
+
+ public function getLinterName() {
+ return 'CHECKSTYLE';
+ }
+
+ public function getInfoURI() {
+ return 'http://checkstyle.sourceforge.net';
+ }
+
+ public function getInfoDescription() {
+ return pht('Use `%s` to perform static analysis on Java code.',
+ 'checkstyle');
+ }
+
+ public function getLinterConfigurationName() {
+ return 'checkstyle';
+ }
+
+ public function getLinterConfigurationOptions() {
+ $options = array(
+ 'checkstyle.simplify-source-classname' => array(
+ 'type' => 'optional bool',
+ 'help' => pht(
+ 'Lint messages reported by checkstyle indicate their source '.
+ 'as the fully-qualified classname of the respective module. '.
+ 'Set this value to true to simplify the classname, such as: '.
+ '`com.company.pkg.IndentationCheck` => `IndentationCheck`.'),
+ ),
+ );
+
+ return $options + parent::getLinterConfigurationOptions();
+ }
+
+ public function setLinterConfigurationValue($key, $value) {
+ switch ($key) {
+ case 'checkstyle.simplify-source-classname':
+ $this->setSimplifySourceClassname($value);
+ return;
+ }
+
+ return parent::setLinterConfigurationValue($key, $value);
+ }
+
+ public function setSimplifySourceClassname($simplify_source_classname) {
+ $this->simplifySourceClassname = $simplify_source_classname;
+ return $this;
+ }
+
+ public function getVersion() {
+ list($stdout) = execx('%C -v', $this->getExecutableCommand());
+
+ $matches = array();
+ $regex = '/^Checkstyle version: (?P<version>\d+\.\d+)$/';
+ if (preg_match($regex, $stdout, $matches)) {
+ return $matches['version'];
+ }
+ return false;
+ }
+
+ public function getInstallInstructions() {
+ return pht('Ensure java is configured as interpreter and '.
+ 'the checkstyle jar is configured as the binary. If you need to pass '.
+ 'additional additional JVM arguments include them with the '.
+ '`interpreter.flags` field. Use the `flags` field to configure '.
+ 'checkstyle arguments, including the `-c my_styles.xml` for '.
+ 'the styles to verify.');
+ }
+
+ protected function getMandatoryFlags() {
+ return array('-f', 'xml');
+ }
+
+ public function shouldExpectCommandErrors() {
+ return false;
+ }
+
+ public function shouldUseInterpreter() {
+ return true;
+ }
+
+ public function getDefaultBinary() {
+ return 'checkstyle.jar';
+ }
+
+ public function getDefaultInterpreter() {
+ return 'java';
+ }
+
+ protected function getMandatoryInterpreterFlags() {
+ // since the binary is the checkstyle jar, this flag must
+ // always be passed to the interpreter, and is guaranteed to be provided
+ // as the first flag before the binary jar on the command line
+ return array('-jar');
+ }
+
+ protected function parseLinterOutput($path, $err, $stdout, $stderr) {
+ $dom = new DOMDocument();
+ $ok = @$dom->loadXML($stdout);
+
+ if (!$ok) {
+ return false;
+ }
+
+ $files = $dom->getElementsByTagName('file');
+ $messages = array();
+ foreach ($files as $file) {
+ $errors = $file->getElementsByTagName('error');
+ foreach ($errors as $error) {
+ $message = new ArcanistLintMessage();
+ $message->setPath($file->getAttribute('name'));
+ $message->setLine($error->getAttribute('line'));
+ $message->setCode($this->getLinterName());
+
+ // source is the module's fully-qualified classname
+ // attempt to simplify it for readability
+ $source = $error->getAttribute('source');
+ if ($this->simplifySourceClassname) {
+ $source = idx(array_slice(explode('.', $source), -1), 0);
+ }
+ $message->setName($source);
+
+ // checkstyle's XMLLogger escapes these five characters
+ $description = $error->getAttribute('message');
+ $description = str_replace(
+ ['&lt;', '&gt;', '&apos;', '&quot;', '&amp;'],
+ ['<', '>', '\'', '"', '&'],
+ $description);
+ $message->setDescription($description);
+
+ $column = $error->getAttribute('column');
+ if ($column) {
+ $message->setChar($column);
+ }
+
+ $severity = $error->getAttribute('severity');
+ switch ($severity) {
+ case 'error':
+ $message->setSeverity(ArcanistLintSeverity::SEVERITY_ERROR);
+ break;
+ case 'warning':
+ $message->setSeverity(ArcanistLintSeverity::SEVERITY_WARNING);
+ break;
+ case 'info':
+ $message->setSeverity(ArcanistLintSeverity::SEVERITY_ADVICE);
+ break;
+ case 'ignore':
+ $message->setSeverity(ArcanistLintSeverity::SEVERITY_DISABLED);
+ break;
+
+ // The above four are the only valid checkstyle severities,
+ // this is for completion as well as preparing for future severities
+ default:
+ $message->setSeverity(ArcanistLintSeverity::SEVERITY_WARNING);
+ break;
+ }
+
+ $messages[] = $message;
+ }
+ }
+
+ return $messages;
+ }
+}
diff --git a/src/lint/linter/ArcanistExternalLinter.php b/src/lint/linter/ArcanistExternalLinter.php
--- a/src/lint/linter/ArcanistExternalLinter.php
+++ b/src/lint/linter/ArcanistExternalLinter.php
@@ -14,6 +14,7 @@
private $interpreter;
private $flags;
private $versionRequirement;
+ private $interpreterFlags;
/* -( Interpreters, Binaries and Flags )----------------------------------- */
@@ -197,6 +198,52 @@
return $this;
}
+ /**
+ * Return array of flags needed by the interpreter, such as "-jar" when
+ * using java as the interpreter. This method is only invoked if
+ * @{method:shouldUseInterpreter} has been overridden to return 'true'.
+ *
+ * @return array Flags to pass to interpreter
+ * @task bin
+ */
+ protected function getDefaultInterpreterFlags() {
+ return array();
+ }
+
+ /**
+ * Provide mandatory, non-overridable flags to the linter interpreter.
+ * Generally these are arguments to configure invocation of the interpreter
+ * such as (assuming Java interpreter) `-Xmx1024m`, `-Dproperty=value`, or
+ * in the case of the binary being a jar file, the last one should be `-jar`.
+ *
+ * Due to the specific case of using java as interpreter and a jarfile as
+ * the binary, the `-jar` argument must appear last in the list of all
+ * flags passed to interpreter. For this, manadatory flags are ensured to
+ * always be listed before any default or user overridden flags.
+ *
+ * Flags which are not mandatory should be provided in
+ * @{method:getDefaultInterpreterFlags} instead.
+ *
+ * @return list<string> Mandatory flags, like `"-jar"`.
+ * @task bin
+ */
+ protected function getMandatoryInterpreterFlags() {
+ return array();
+ }
+
+ /**
+ * Override default interpreter flags with custom flags. If not overridden,
+ * flags provided by @{method:getDefaultInterpreterFlags} are used.
+ *
+ * @param list<string> New flags for the interpreter.
+ * @return this
+ * @task bin
+ */
+ final public function setInterpreterFlags(array $interpreter_flags) {
+ $this->interpreterFlags = $interpreter_flags;
+ return $this;
+ }
+
/* -( Parsing Linter Output )---------------------------------------------- */
@@ -351,14 +398,20 @@
$this->checkBinaryConfiguration();
$interpreter = null;
+ $interpreter_flags = array();
if ($this->shouldUseInterpreter()) {
$interpreter = $this->getInterpreter();
+ $interpreter_flags = $this->getInterpreterFlags();
}
$binary = $this->getBinary();
if ($interpreter) {
- $bin = csprintf('%s %s', $interpreter, $binary);
+ if (!empty($interpreter_flags)) {
+ $bin = csprintf('%s %Ls %s', $interpreter, $interpreter_flags, $binary);
+ } else {
+ $bin = csprintf('%s %s', $interpreter, $binary);
+ }
} else {
$bin = csprintf('%s', $binary);
}
@@ -379,6 +432,23 @@
nonempty($this->flags, $this->getDefaultFlags()));
}
+ /**
+ * Get the composed flags for the interpreter, including both mandatory and
+ * configured flags.
+ *
+ * @return list<string> Composed interpreter flags.
+ * @task exec
+ */
+ final protected function getInterpreterFlags() {
+ // Note that this forces the mandatory flags to appear before any other
+ // flags provided through default or overridden. This is to handle the
+ // the case of java interpreter needing to combine the `-jar` flag followed
+ // immediately by the binary which would be the jar file.
+ return array_merge(
+ nonempty($this->interpreterFlags, $this->getDefaultInterpreterFlags()),
+ $this->getMandatoryInterpreterFlags());
+ }
+
public function getCacheVersion() {
try {
$this->checkBinaryConfiguration();
@@ -495,6 +565,13 @@
'a list of possible interpreters, the first one that exists '.
'will be used.'),
);
+
+ $options['interpreter.flags'] = array(
+ 'type' => 'optional list<string>',
+ 'help' => pht(
+ 'Provide a list of additional flags to pass to the interpreter on '.
+ 'the command line.'),
+ );
}
return $options + parent::getLinterConfigurationOptions();
@@ -545,6 +622,9 @@
case 'flags':
$this->setFlags($value);
return;
+ case 'interpreter.flags':
+ $this->setInterpreterFlags($value);
+ return;
case 'version':
$this->setVersionRequirement($value);
return;
diff --git a/src/lint/linter/ArcanistPMDLinter.php b/src/lint/linter/ArcanistPMDLinter.php
new file mode 100644
--- /dev/null
+++ b/src/lint/linter/ArcanistPMDLinter.php
@@ -0,0 +1,264 @@
+<?php
+
+/**
+ * This linter invokes PMD for linting java code.
+ * The PMD report is given over stdout as a simple XML document
+ * which maps fairly easily to ArcanistLintMessage.
+ *
+ * The manner of executing PMD is a little round-about in order
+ * to work around the internals of ArcanistExternalLinter.
+ *
+ * The binary is passed as a classpath argument to `java` then
+ * the binary arguments override it with a full classpath.
+ * This also enables the binary being used to build the full
+ * classpath since the PMD distribution uses multiple jars.
+ */
+class ArcanistPMDLinter extends ArcanistExternalLinter {
+
+ private $subCommand = 'pmd';
+
+ public function getInfoName() {
+ return 'Java PMD linter';
+ }
+
+ public function getLinterName() {
+ return 'PMD';
+ }
+
+ public function getInfoURI() {
+ return 'https://pmd.github.io/';
+ }
+
+ public function getInfoDescription() {
+ return pht('Use `%s` to perform static analysis on Java code.',
+ 'PMD');
+ }
+
+ public function getLinterConfigurationName() {
+ return 'pmd';
+ }
+
+ public function getLinterConfigurationOptions() {
+ $options = array(
+ 'pmd.command' => array(
+ 'type' => 'optional string',
+ 'help' => pht(
+ 'Specify the subcommand to run, defaults to `pmd`. '.
+ 'Available subcommands are `pmd` or `cpd`. See the PMD '.
+ 'documentation for more: '.
+ 'https://pmd.github.io/pmd-5.4.1/usage/running.html'),
+ ),
+ );
+
+ return $options + parent::getLinterConfigurationOptions();
+ }
+
+ public function setLinterConfigurationValue($key, $value) {
+ switch ($key) {
+ case 'pmd.command':
+ $this->setSubCommand($value);
+ return;
+ }
+
+ return parent::setLinterConfigurationValue($key, $value);
+ }
+
+ public function setSubCommand($sub_command) {
+ $this->subCommand = $sub_command;
+ return $this;
+ }
+
+ public function getVersion() {
+ // The pmd executable doesn't appear to actually be able to print a version
+ // However if you run the binary, the help output gives examples that
+ // appear to display the version number in paths...
+ $interpreter = $this->getInterpreter();
+ $classpath = $this->buildClasspath();
+ $mainclass = $this->getSubCommandMainClass();
+
+ // having the help printout for PMD returns with error code 4.
+ list($code, $stdout, $stderr) = exec_manual('%s -cp %s %s',
+ $interpreter, $classpath, $mainclass);
+
+ $matches = array();
+ $regex = '/^\$ pmd-bin-(?P<version>\d+\.\d+\.\d+)/m';
+ if (preg_match($regex, $stdout, $matches)) {
+ return $matches['version'];
+ }
+ return false;
+ }
+
+ public function getInstallInstructions() {
+ return pht('Ensure java is configured as interpreter and '.
+ 'the pmd jar is configured as the binary. If you need to pass '.
+ 'additional additional JVM arguments include them with the '.
+ '`interpreter` field. Use the `flags` field to configure pmd '.
+ 'arguments, including the `-rulesets my_rulesets.xml`. '.
+ 'You must pass the `-dir` argument as the last flag.');
+ }
+
+ protected function getMandatoryFlags() {
+ $classpath = $this->buildClasspath();
+ $subcommand_mainclass = $this->getSubCommandMainClass();
+ return array(
+ '-cp',
+ $classpath,
+ $subcommand_mainclass,
+ '-failOnViolation',
+ 'false',
+ '-format',
+ 'xml',
+ );
+ }
+
+ public function shouldExpectCommandErrors() {
+ return false;
+ }
+
+ public function shouldUseInterpreter() {
+ return true;
+ }
+
+ public function getDefaultBinary() {
+ return 'pmd-core.jar';
+ }
+
+ public function getDefaultInterpreter() {
+ return 'java';
+ }
+
+ protected function getMandatoryInterpreterFlags() {
+ // this causes the jar binary to be interpreted as classpath
+ // later to be overwritten with a full classpath during execution
+ return array('-cp');
+ }
+
+ protected function parseLinterOutput($path, $err, $stdout, $stderr) {
+ $dom = new DOMDocument();
+ $ok = @$dom->loadXML($stdout);
+
+ if (!$ok) {
+ return false;
+ }
+
+ $files = $dom->getElementsByTagName('file');
+ $messages = array();
+ foreach ($files as $file) {
+ $violations = $file->getElementsByTagName('violation');
+ foreach ($violations as $violation) {
+ $message = new ArcanistLintMessage();
+ $message->setPath($file->getAttribute('name'));
+ $message->setLine($violation->getAttribute('beginline'));
+ $message->setCode($this->getLinterName());
+
+ // include the ruleset and the rule
+ $message->setName($violation->getAttribute('ruleset').
+ ': '.$violation->getAttribute('rule'));
+
+ $description = '';
+ if (property_exists($violation, 'firstChild')) {
+ $first_child = $violation->firstChild;
+ if (property_exists($first_child, 'wholeText')) {
+ $description = $first_child->wholeText;
+ }
+ }
+
+ // unescape the XML written out by pmd's XMLRenderer
+ if ($description) {
+ // these 4 characters use specific XML-escape codes
+ $description = str_replace(
+ ['&amp;', '&quot;', '&lt;', '&gt;'],
+ ['&', '"', '<', '>'],
+ $description);
+
+ // everything else is hex-code escaped
+ $escaped_chars = array();
+ preg_replace_callback(
+ '/&#x(?P<hexcode>[a-f|A-F|0-9]+);/',
+ array($this, 'callbackReplaceMatchesWithHexcode'),
+ $description);
+
+ $message->setDescription($description);
+ }
+
+ $column = $violation->getAttribute('begincolumn');
+ if ($column) {
+ $message->setChar($column);
+ }
+
+ $severity = $violation->getAttribute('priority');
+ switch ($severity) {
+ case '1':
+ $message->setSeverity(ArcanistLintSeverity::SEVERITY_ERROR);
+ break;
+ case '2':
+ $message->setSeverity(ArcanistLintSeverity::SEVERITY_WARNING);
+ break;
+ case '3':
+ case '4':
+ case '5':
+ $message->setSeverity(ArcanistLintSeverity::SEVERITY_ADVICE);
+ break;
+
+ // The above five are the only valid PMD priorities,
+ // this is for completion as well as preparing for future severities
+ default:
+ $message->setSeverity(ArcanistLintSeverity::SEVERITY_WARNING);
+ break;
+ }
+
+ $messages[] = $message;
+ }
+ }
+
+ return $messages;
+ }
+
+ private function buildClasspath() {
+ $jar_files = array();
+ $lib_path = Filesystem::resolvePath($this->getBinary());
+ $lib_path = substr($lib_path, 0, strrpos($lib_path, DIRECTORY_SEPARATOR));
+
+ $lib_path_contents = Filesystem::listDirectory($lib_path);
+ foreach ($lib_path_contents as $lib_path_file) {
+ if (preg_match('/\.jar$/', $lib_path_file)) {
+ $jar_files[] = $lib_path.DIRECTORY_SEPARATOR.$lib_path_file;
+ }
+ }
+ return implode(PATH_SEPARATOR, $jar_files);
+ }
+
+ private function getSubCommandMainClass() {
+ $command_mainclass = '';
+ switch ($this->subCommand) {
+ case 'pmd':
+ $command_mainclass = 'net.sourceforge.pmd.PMD';
+ break;
+ case 'cpd':
+ $command_mainclass = 'net.sourceforge.pmd.cpd.CPD';
+ break;
+ }
+ return $command_mainclass;
+ }
+
+ private function callbackReplaceMatchesWithHexcode($matches) {
+ return $this->convertHexToBin($matches['hexcode']);
+ }
+
+ /**
+ * This is a replacement for hex2bin() which is only available in PHP 5.4+.
+ * Returns the ascii interpretation of a given hexadecimal string.
+ *
+ * @param $str string The hexadecimal string to interpret
+ *
+ * @return string The string of characters represented by the given hex codes
+ */
+ private function convertHexToBin($str) {
+ $sbin = '';
+ $len = strlen($str);
+ for ($i = 0; $i < $len; $i += 2) {
+ $sbin .= pack('H*', substr($str, $i, 2));
+ }
+ return $sbin;
+ }
+}
diff --git a/src/lint/linter/__tests__/ArcanistCheckstyleLinterTestCase.php b/src/lint/linter/__tests__/ArcanistCheckstyleLinterTestCase.php
new file mode 100644
--- /dev/null
+++ b/src/lint/linter/__tests__/ArcanistCheckstyleLinterTestCase.php
@@ -0,0 +1,17 @@
+<?php
+
+final class ArcanistCheckstyleLinterTestCase
+ extends ArcanistExternalLinterTestCase {
+
+ protected function getLinter() {
+ $linter = parent::getLinter();
+ $linter->setBinary('/usr/local/bin/checkstyle-6.13-all.jar');
+ $linter->setFlags(
+ array('-c', dirname(__FILE__).'/checkstyle/google_checks.xml'));
+ return $linter;
+ }
+
+ public function testLinter() {
+ $this->executeTestsInDirectory(dirname(__FILE__).'/checkstyle/');
+ }
+}
diff --git a/src/lint/linter/__tests__/ArcanistLinterTestCase.php b/src/lint/linter/__tests__/ArcanistLinterTestCase.php
--- a/src/lint/linter/__tests__/ArcanistLinterTestCase.php
+++ b/src/lint/linter/__tests__/ArcanistLinterTestCase.php
@@ -60,9 +60,9 @@
'~~~~~~~~~~'));
}
- list($data, $expect, $xform, $config) = array_merge(
+ list($data, $expect, $xform, $config, $tmp_filename) = array_merge(
$contents,
- array(null, null));
+ array(null, null, null));
$basename = basename($file);
@@ -87,7 +87,10 @@
$caught_exception = false;
try {
- $tmp = new TempFile($basename);
+ if (!$tmp_filename) {
+ $tmp_filename = $basename;
+ }
+ $tmp = new TempFile($tmp_filename);
Filesystem::writeFile($tmp, $data);
$full_path = (string)$tmp;
diff --git a/src/lint/linter/__tests__/checkstyle/google_checks.lint-test b/src/lint/linter/__tests__/checkstyle/google_checks.lint-test
new file mode 100644
--- /dev/null
+++ b/src/lint/linter/__tests__/checkstyle/google_checks.lint-test
@@ -0,0 +1,28 @@
+public class TestingCheckstyle {
+ public static void main(String[] args)
+ {
+ System.out.println()
+ }
+
+ private class A{
+
+ @Override public String m() { return null; }
+ }
+}
+~~~~~~~~~~
+warning:1:
+warning:3:3
+warning:4:
+warning:7:18
+warning:9:
+warning:9:31
+warning:9:46
+~~~~~~~~~~
+~~~~~~~~~~
+{
+ "config": {
+ "checkstyle.simplify-source-classname": true
+ }
+}
+~~~~~~~~~~
+google_checks.lint-test.java
\ No newline at end of file
diff --git a/src/lint/linter/__tests__/checkstyle/google_checks.xml b/src/lint/linter/__tests__/checkstyle/google_checks.xml
new file mode 100644
--- /dev/null
+++ b/src/lint/linter/__tests__/checkstyle/google_checks.xml
@@ -0,0 +1,206 @@
+<?xml version="1.0"?>
+<!DOCTYPE module PUBLIC
+ "-//Puppy Crawl//DTD Check Configuration 1.3//EN"
+ "http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
+
+<!--
+
+ Checkstyle configuration that checks the Google coding conventions from:
+
+ - Google Java Style
+ https://google-styleguide.googlecode.com/svn-history/r130/trunk/javaguide.html
+
+ Checkstyle is very configurable. Be sure to read the documentation at
+ http://checkstyle.sf.net (or in your downloaded distribution).
+
+ Most Checks are configurable, be sure to consult the documentation.
+
+ To completely disable a check, just comment it out or delete it from the file.
+
+ Authors: Max Vetrenko, Ruslan Diachenko, Roman Ivanov.
+
+ -->
+
+<module name = "Checker">
+ <property name="charset" value="UTF-8"/>
+
+ <property name="severity" value="warning"/>
+
+ <property name="fileExtensions" value="java, properties, xml"/>
+ <!-- Checks for whitespace -->
+ <!-- See http://checkstyle.sf.net/config_whitespace.html -->
+ <module name="FileTabCharacter">
+ <property name="eachLine" value="true"/>
+ </module>
+
+ <module name="TreeWalker">
+ <module name="OuterTypeFilename"/>
+ <module name="IllegalTokenText">
+ <property name="tokens" value="STRING_LITERAL, CHAR_LITERAL"/>
+ <property name="format" value="\\u00(08|09|0(a|A)|0(c|C)|0(d|D)|22|27|5(C|c))|\\(0(10|11|12|14|15|42|47)|134)"/>
+ <property name="message" value="Avoid using corresponding octal or Unicode escape."/>
+ </module>
+ <module name="AvoidEscapedUnicodeCharacters">
+ <property name="allowEscapesForControlCharacters" value="true"/>
+ <property name="allowByTailComment" value="true"/>
+ <property name="allowNonPrintableEscapes" value="true"/>
+ </module>
+ <module name="LineLength">
+ <property name="max" value="100"/>
+ <property name="ignorePattern" value="^package.*|^import.*|a href|href|http://|https://|ftp://"/>
+ </module>
+ <module name="AvoidStarImport"/>
+ <module name="OneTopLevelClass"/>
+ <module name="NoLineWrap"/>
+ <module name="EmptyBlock">
+ <property name="option" value="TEXT"/>
+ <property name="tokens" value="LITERAL_TRY, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE, LITERAL_SWITCH"/>
+ </module>
+ <module name="NeedBraces"/>
+ <module name="LeftCurly">
+ <property name="maxLineLength" value="100"/>
+ </module>
+ <module name="RightCurly"/>
+ <module name="RightCurly">
+ <property name="option" value="alone"/>
+ <property name="tokens" value="CLASS_DEF, METHOD_DEF, CTOR_DEF, LITERAL_FOR, LITERAL_WHILE, LITERAL_DO, STATIC_INIT, INSTANCE_INIT"/>
+ </module>
+ <module name="WhitespaceAround">
+ <property name="allowEmptyConstructors" value="true"/>
+ <property name="allowEmptyMethods" value="true"/>
+ <property name="allowEmptyTypes" value="true"/>
+ <property name="allowEmptyLoops" value="true"/>
+ <message key="ws.notFollowed"
+ value="WhitespaceAround: ''{0}'' is not followed by whitespace. Empty blocks may only be represented as '{}' when not part of a multi-block statement (4.1.3)"/>
+ <message key="ws.notPreceded"
+ value="WhitespaceAround: ''{0}'' is not preceded with whitespace."/>
+ </module>
+ <module name="OneStatementPerLine"/>
+ <module name="MultipleVariableDeclarations"/>
+ <module name="ArrayTypeStyle"/>
+ <module name="MissingSwitchDefault"/>
+ <module name="FallThrough"/>
+ <module name="UpperEll"/>
+ <module name="ModifierOrder"/>
+ <module name="EmptyLineSeparator">
+ <property name="allowNoEmptyLineBetweenFields" value="true"/>
+ </module>
+ <module name="SeparatorWrap">
+ <property name="tokens" value="DOT"/>
+ <property name="option" value="nl"/>
+ </module>
+ <module name="SeparatorWrap">
+ <property name="tokens" value="COMMA"/>
+ <property name="option" value="EOL"/>
+ </module>
+ <module name="PackageName">
+ <property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$"/>
+ <message key="name.invalidPattern"
+ value="Package name ''{0}'' must match pattern ''{1}''."/>
+ </module>
+ <module name="TypeName">
+ <message key="name.invalidPattern"
+ value="Type name ''{0}'' must match pattern ''{1}''."/>
+ </module>
+ <module name="MemberName">
+ <property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9]*$"/>
+ <message key="name.invalidPattern"
+ value="Member name ''{0}'' must match pattern ''{1}''."/>
+ </module>
+ <module name="ParameterName">
+ <property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9]*$"/>
+ <message key="name.invalidPattern"
+ value="Parameter name ''{0}'' must match pattern ''{1}''."/>
+ </module>
+ <module name="LocalVariableName">
+ <property name="tokens" value="VARIABLE_DEF"/>
+ <property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9]*$"/>
+ <property name="allowOneCharVarInForLoop" value="true"/>
+ <message key="name.invalidPattern"
+ value="Local variable name ''{0}'' must match pattern ''{1}''."/>
+ </module>
+ <module name="ClassTypeParameterName">
+ <property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
+ <message key="name.invalidPattern"
+ value="Class type name ''{0}'' must match pattern ''{1}''."/>
+ </module>
+ <module name="MethodTypeParameterName">
+ <property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
+ <message key="name.invalidPattern"
+ value="Method type name ''{0}'' must match pattern ''{1}''."/>
+ </module>
+ <module name="NoFinalizer"/>
+ <module name="GenericWhitespace">
+ <message key="ws.followed"
+ value="GenericWhitespace ''{0}'' is followed by whitespace."/>
+ <message key="ws.preceded"
+ value="GenericWhitespace ''{0}'' is preceded with whitespace."/>
+ <message key="ws.illegalFollow"
+ value="GenericWhitespace ''{0}'' should followed by whitespace."/>
+ <message key="ws.notPreceded"
+ value="GenericWhitespace ''{0}'' is not preceded with whitespace."/>
+ </module>
+ <module name="Indentation">
+ <property name="basicOffset" value="2"/>
+ <property name="braceAdjustment" value="0"/>
+ <property name="caseIndent" value="2"/>
+ <property name="throwsIndent" value="4"/>
+ <property name="lineWrappingIndentation" value="4"/>
+ <property name="arrayInitIndent" value="2"/>
+ </module>
+ <module name="AbbreviationAsWordInName">
+ <property name="ignoreFinal" value="false"/>
+ <property name="allowedAbbreviationLength" value="1"/>
+ </module>
+ <module name="OverloadMethodsDeclarationOrder"/>
+ <module name="VariableDeclarationUsageDistance"/>
+ <module name="CustomImportOrder">
+ <property name="specialImportsRegExp" value="com.google"/>
+ <property name="sortImportsInGroupAlphabetically" value="true"/>
+ <property name="customImportOrderRules" value="STATIC###SPECIAL_IMPORTS###THIRD_PARTY_PACKAGE###STANDARD_JAVA_PACKAGE"/>
+ </module>
+ <module name="MethodParamPad"/>
+ <module name="OperatorWrap">
+ <property name="option" value="NL"/>
+ <property name="tokens" value="BAND, BOR, BSR, BXOR, DIV, EQUAL, GE, GT, LAND, LE, LITERAL_INSTANCEOF, LOR, LT, MINUS, MOD, NOT_EQUAL, PLUS, QUESTION, SL, SR, STAR "/>
+ </module>
+ <module name="AnnotationLocation">
+ <property name="tokens" value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF"/>
+ </module>
+ <module name="AnnotationLocation">
+ <property name="tokens" value="VARIABLE_DEF"/>
+ <property name="allowSamelineMultipleAnnotations" value="true"/>
+ </module>
+ <module name="NonEmptyAtclauseDescription"/>
+ <module name="JavadocTagContinuationIndentation"/>
+ <module name="SummaryJavadocCheck">
+ <property name="forbiddenSummaryFragments" value="^@return the *|^This method returns |^A [{]@code [a-zA-Z0-9]+[}]( is a )"/>
+ </module>
+ <module name="JavadocParagraph"/>
+ <module name="AtclauseOrder">
+ <property name="tagOrder" value="@param, @return, @throws, @deprecated"/>
+ <property name="target" value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF, VARIABLE_DEF"/>
+ </module>
+ <module name="JavadocMethod">
+ <property name="scope" value="public"/>
+ <property name="allowMissingParamTags" value="true"/>
+ <property name="allowMissingThrowsTags" value="true"/>
+ <property name="allowMissingReturnTag" value="true"/>
+ <property name="minLineCount" value="2"/>
+ <property name="allowedAnnotations" value="Override, Test"/>
+ <property name="allowThrowsTagsForSubclasses" value="true"/>
+ </module>
+ <module name="MethodName">
+ <property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9_]*$"/>
+ <message key="name.invalidPattern"
+ value="Method name ''{0}'' must match pattern ''{1}''."/>
+ </module>
+ <module name="SingleLineJavadoc">
+ <property name="ignoreInlineTags" value="false"/>
+ </module>
+ <module name="EmptyCatchBlock">
+ <property name="exceptionVariableName" value="expected"/>
+ </module>
+ <module name="CommentsIndentation"/>
+ </module>
+</module>

File Metadata

Mime Type
text/plain
Expires
Mon, Mar 17, 10:53 PM (4 d, 16 h ago)
Storage Engine
amazon-s3
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
phabricator/secure/g4/tr/mwpgmej6t2ty7ji2
Default Alt Text
D14632.id35533.diff (33 KB)

Event Timeline