<?xml version="1.0"?>
<!DOCTYPE module PUBLIC
    "-//Puppy Crawl//DTD Check Configuration 1.3//EN"
    "http://www.puppycrawl.com/dtds/configuration_1_3.dtd">

<module name="Checker">
  <module name="BeforeExecutionExclusionFileFilter">
   <property name="fileNamePattern" value="module\-info\.java$"/>
  </module>

  <property name="charset" value="UTF-8" />

  <module name="SuppressionFilter">
    <property name="file" value="${config_loc}/checkstyle_suppressions.xml" />
  </module>

  <module name="SuppressionFilter">
    <property name="file" value="${config_loc}/additional_checkstyle_suppressions.xml" />
    <property name="optional" value="true" />
  </module>

  <module name="SuppressWarningsFilter" />

  <module name="RegexpMultiline">
    <property name="id" value="MultipleHeaderJavadoc" />
    <property name="format" value="^\s*\/\*\r?\n(\s\*[A-Za-z0-9 \.\/\;\,\.\-\(\)\\\x{22}\/\:\@\=\'\]\[\_\x{3E}\x{3C}]*\r?\n)+(\s\*\/)\s+package" />
    <property name="fileExtensions" value="java" />
    <property name="minimum" value="1" />
    <property name="maximum" value="1" />
    <property name="matchAcrossLines" value="true" />
    <property name="message" value="Duplicate header javadocs are forbidden" />
  </module>

  <!-- Checks Java files and forbids empty Javadoc comments. -->
  <!-- Although you can use the "JavadocStyle" rule for this, it considers Javadoc -->
  <!-- that only contains a "@return" line to be empty. -->
  <module name="RegexpMultiline">
    <property name="id" value="EmptyJavadoc" />
    <property name="format" value="\/\*[\s\*]*\*\/" />
    <property name="fileExtensions" value="java" />
    <property name="message" value="Empty javadoc comments are forbidden" />
  </module>

  <!--
    We include snippets that are wrapped in `// tag` and `// end` into the
    docs, stripping the leading spaces. If the context is wider than 76
    characters then it'll need to scroll. This fails the build if it sees
    such snippets.
  -->
  <module name="org.elasticsearch.gradle.internal.checkstyle.SnippetLengthCheck">
    <property name="id" value="SnippetLength" />
    <property name="max" value="76" />
  </module>

  <!-- Its our official line length! See checkstyle_suppressions.xml for the files that don't pass this. For now we
    suppress the check there but enforce it everywhere else. This prevents the list from getting longer even if it is
    unfair. -->
  <module name="LineLength">
    <property name="max" value="140" />
    <property name="ignorePattern" value="^(?:(?:package|import) .*| *\*.*https?://.*)$" />
  </module>

  <module name="TreeWalker">
    <!-- Make the @SuppressWarnings annotations available to Checkstyle -->
    <module name="SuppressWarningsHolder" />

    <module name="AvoidStarImport" />

    <!-- Unused imports are forbidden -->
    <module name="UnusedImports" />
    <module name="SuppressionCommentFilter">
      <property name="offCommentFormat" value="begin generated imports"/>
      <property name="onCommentFormat" value="end generated imports"/>
      <property name="checkFormat" value="UnusedImports"/>
    </module>

    <!-- Non-inner classes must be in files that match their names. -->
    <module name="OuterTypeFilename" />

    <!-- No line wraps inside of import and package statements. -->
    <module name="NoLineWrap" />

    <!-- only one statement per line should be allowed -->
    <module name="OneStatementPerLine" />

    <!-- Each java file has only one outer class -->
    <module name="OneTopLevelClass" />

    <!-- The suffix L is preferred, because the letter l (ell) is often
      hard to distinguish from the digit 1 (one). -->
    <module name="UpperEll" />

    <module name="EqualsHashCode" />

    <!-- Checks that the order of modifiers conforms to the suggestions in the
    Java Language specification, sections 8.1.1, 8.3.1 and 8.4.3. It is not that
    the standard is perfect, but having a consistent order makes the code more
    readable and no other order is compellingly better than the standard.
    The correct order is:
            public
            protected
            private
            abstract
            static
            final
            transient
            volatile
            synchronized
            native
            strictfp
    -->
    <module name="ModifierOrder" />

    <!-- Checks that we don't include modifier where they are implied. For
      example, this does not allow interface methods to be declared public
      because they are *always* public. -->
    <module name="RedundantModifier" />
    <!-- Checks that all java files have a package declaration and that it
      lines up with the directory structure. -->
    <module name="PackageDeclaration" />

    <!-- Checks that a local variable or a parameter does not shadow a field that is defined in the same class. -->
    <!-- Use a forked version that understands setters that don't start with "set". -->
    <!-- Notes on `ignoredMethodNames`:

        * `createParser` creates objects so should be considered a sort-of constructor
        * `createComponents` by its nature ends up referring to fields
          a lot, and there's no benefit to flagging shadowed variables in
          those methods.
    -->
    <!-- Disabled until existing violations are fixed -->
    <!--
    <module name="org.elasticsearch.gradle.internal.checkstyle.HiddenFieldCheck">
        <property name="ignoreConstructorParameter" value="true" />
        <property name="ignoreConstructorBody" value="true"/>
        <property name="ignoreConstructorMethods" value="(?:ConstructingObjectParser)$"/>
        <property name="ignoreSetter" value="true" />
        <property name="minLineCount" value="5" />
        <property name="ignoreFormat" value="^(?:threadPool)$"/>
        <property name="ignoreAbstractMethods" value="true"/>
        <property name="ignoreMethodNames" value="^(?:createParser|createComponents)$"/>
        <property name="setterCanReturnItsClass" value="true"/>
        <message key="hidden.field" value="''{0}'' hides a field." />
    </module>
    -->

    <module name="org.elasticsearch.gradle.internal.checkstyle.StringFormattingCheck">
        <message
            key="forbidden.formatted"
            value="''{0}'' format specifier is unsafe inside ''.formatted'' calls, as it uses the default locale. Use ''String.format'' for numeric formatting with ''Locale.ROOT'' instead." />
    </module>

    <module name="org.elasticsearch.gradle.internal.checkstyle.SwitchBetweenCheck">
        <message
            key="forbidden.switch.between"
            value="Case ''{0}'' is outside the range of the ''{1}({2}, {3})'' call of the enclosing switch." />
        <message
            key="forbidden.switch.randomInt"
            value="Case ''{0}'' is outside the range of the ''{1}({2})'' call of the enclosing switch." />
    </module>

    <!-- We don't use Java's builtin serialization and we suppress all warning
      about it. The flip side of that coin is that we shouldn't _try_ to use
      it. We can't outright ban it with ForbiddenApis because it complain about
      every we reference a class that implements Serializable like String or
      Exception.
      -->
    <module name="RegexpSinglelineJava">
      <property name="format" value="serialVersionUID" />
      <property name="message" value="Do not declare serialVersionUID." />
      <property name="ignoreComments" value="true" />
    </module>
    <module name="RegexpSinglelineJava">
      <property name="format" value="java\.io\.Serializable;" />
      <property name="message" value="References java.io.Serializable." />
      <property name="ignoreComments" value="true" />
    </module>
    <!-- end Orwellian suppression of Serializable -->

    <!-- Forbid equality comparisons with `true` -->
    <module name="DescendantToken">
      <property name="id" value="EqualityWithTrue" />
      <property name="tokens" value="EQUAL" />
      <property name="limitedTokens" value="LITERAL_TRUE" />
      <property name="maximumNumber" value="0" />
      <property name="maximumDepth" value="1" />
      <message key="descendant.token.max" value="Do not check for equality with 'true', since it is implied" />
    </module>

    <!-- Forbid using '!' for logical negations in favour of checking against 'false' explicitly. -->
    <!-- This is only reported in the IDE for now because there are many violations -->
    <module name="DescendantToken">
        <property name="id" value="BooleanNegation" />
        <property name="tokens" value="EXPR"/>
        <property name="limitedTokens" value="LNOT"/>
        <property name="maximumNumber" value="0"/>
        <message
            key="descendant.token.max"
            value="Do not negate boolean expressions with '!', but check explicitly with '== false' as it is more explicit"/>
    </module>

    <module name="NeedBraces">
        <!-- We have many generated equals classes with LITERAL_IF and no braces, so we don't check IF or ELSE -->
        <property name="tokens" value="LITERAL_DO,LITERAL_FOR,LITERAL_WHILE"/>
        <property name="allowSingleLineStatement" value="false"/>
        <property name="allowEmptyLoopBody" value="true"/>
    </module>

  </module>
</module>
