All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.netflix.nebula.lint.GradleViolation.groovy Maven / Gradle / Ivy

Go to download

Pluggable and configurable linter tool for identifying and reporting on patterns of misuse or deprecations in Gradle scripts

There is a newer version: 20.2.2
Show newest version
/*
 * Copyright 2015-2019 Netflix, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.netflix.nebula.lint

import com.netflix.nebula.lint.rule.BuildFiles
import groovy.transform.EqualsAndHashCode
import org.codehaus.groovy.ast.ASTNode
import org.codehaus.groovy.ast.expr.ArgumentListExpression
import org.codehaus.groovy.ast.expr.ClosureExpression
import org.codehaus.groovy.ast.expr.MethodCallExpression
import org.codenarc.rule.Rule
import org.codenarc.rule.Violation

import java.util.concurrent.atomic.AtomicInteger

@EqualsAndHashCode(includes = 'id')
class GradleViolation extends Violation {
    public static String DEFAULT_DOCUMENTATION_URI = "https://github.com/nebula-plugins/gradle-lint-plugin/wiki"

    BuildFiles files
    List fixes = []
    int id
    String documentationUri = DEFAULT_DOCUMENTATION_URI

    static AtomicInteger nextId = new AtomicInteger(0)

    GradleViolation(BuildFiles files, Rule rule, Integer lineNumber, String sourceLine, String message) {
        this.files = files
        this.rule = rule
        this.lineNumber = lineNumber
        this.sourceLine = sourceLine
        this.message = message
        this.id = nextId.getAndIncrement()
    }

    File getFile() {
        files.original(super.lineNumber).file
    }

    Integer getLineNumber() {
        files.original(super.lineNumber).line
    }

    GradleViolation insertAfter(ASTNode node, String changes) {
        BuildFiles.Original original = files.original(node.lastLineNumber)
        fixes += new GradleLintInsertAfter(this, original.file, original.line, changes)
        this
    }

    GradleViolation insertBefore(ASTNode node, String changes) {
        BuildFiles.Original original = files.original(node.lineNumber)
        fixes += new GradleLintInsertBefore(this, original.file, original.line, changes)
        this
    }

    GradleViolation insertIntoClosure(ASTNode node, String changes) {
        return insertIntoClosureAt(node, changes, true)
    }

    GradleViolation insertIntoClosureAtTheEnd(ASTNode node, String changes) {
        return insertIntoClosureAt(node, changes, false)
    }

    private void insertIntoClosureAt(ASTNode node, String changes, boolean insertAtStart) {
        ClosureExpression closure = null
        if (node instanceof MethodCallExpression) {
            closure = node.arguments.find { it instanceof ClosureExpression } as ClosureExpression
            if (!closure && node.arguments instanceof ArgumentListExpression) {
                (node.arguments as ArgumentListExpression).expressions.each {
                    insertIntoClosure(it, changes)
                }
            }
        } else if (node instanceof ClosureExpression) {
            closure = node
        }

        // goal: when adding into a closure, it should be indented 4 spaces
        // achieve this by taking the node's (columnNumber-1)+4 OR columnNumber+3

        if (closure) {
            def indentedChanges = changes.stripIndent()
                    .split('\n')
                    .collect { line -> ''.padRight(node.columnNumber + 3) + line }
                    .join('\n')
            if (closure.lineNumber == closure.lastLineNumber) {
                def originalFileText = files.original(closure.lineNumber).file.text
                def originalLine = originalFileText.readLines()[closure.lineNumber-1]
                String originalClosureContent = originalLine.substring(closure.code.columnNumber - 1, closure.code.lastColumnNumber - 1).stripIndent()
                        .split('\n')
                        .collect { line -> ''.padRight(node.columnNumber + 3) + line }
                        .join('\n')
                if (insertAtStart) {
                    replaceWith(closure,'{\n' + indentedChanges + '\n' + originalClosureContent + '\n}')
                } else {
                    replaceWith(closure,'{\n' + originalClosureContent + '\n' + indentedChanges + '\n}')
                }
            } else {
                def lineNumberToStartInsertion = insertAtStart ? closure.lineNumber : closure.lastLineNumber
                BuildFiles.Original original = files.original(lineNumberToStartInsertion)
                if (insertAtStart) {
                    fixes += new GradleLintInsertAfter(this, original.file, original.line, indentedChanges)
                } else {
                    fixes += new GradleLintInsertBefore(this, original.file, original.line, indentedChanges)
                }
            }
        }

        this
    }

    GradleViolation replaceWith(ASTNode node, String changes) {
        BuildFiles.Original original = files.original(node.lineNumber)
        fixes += new GradleLintReplaceWith(this, original.file, original.line..files.original(node.lastLineNumber).line, node.columnNumber,
            node.lastColumnNumber, changes)
        this
    }

    GradleViolation delete(ASTNode node) {
        BuildFiles.Original original = files.original(node.lineNumber)
        fixes += new GradleLintReplaceWith(this, original.file, original.line..files.original(node.lastLineNumber).line, node.columnNumber, node.lastColumnNumber, '')
        this
    }

    GradleViolation insertAfter(File file, Integer afterLine, String changes) {
        fixes += new GradleLintInsertAfter(this, file, afterLine, changes)
        this
    }

    GradleViolation insertBefore(File file, Integer beforeLine, String changes) {
        fixes += new GradleLintInsertBefore(this, file, beforeLine, changes)
        this
    }

    GradleViolation replaceAll(File file, String changes) {
        def lines = file.readLines()
        fixes += new GradleLintReplaceWith(this, file, 1..lines.size(), 1, lines[-1].length() + 1, changes)
        this
    }

    GradleViolation deleteLines(File file, Range linesToDelete) {
        fixes += new GradleLintDeleteLines(this, file, linesToDelete)
        this
    }

    GradleViolation deleteFile(File file) {
        fixes += new GradleLintDeleteFile(this, file)
        this
    }

    GradleViolation createFile(File file, String changes, FileMode fileMode = FileMode.Regular) {
        fixes += new GradleLintCreateFile(this, file, changes, fileMode)
        this
    }

    GradleViolation documentationUri(String documentationUri) {
        this.documentationUri = documentationUri
        this
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy