com.android.build.gradle.internal.LintGradleClient.java Source code

Java tutorial

Introduction

Here is the source code for com.android.build.gradle.internal.LintGradleClient.java

Source

/*
 * Copyright (C) 2013 The Android Open Source Project
 *
 * 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.android.build.gradle.internal;

import static com.android.builder.model.AndroidProject.FD_INTERMEDIATES;
import static java.io.File.separator;

import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
import com.android.builder.model.AndroidProject;
import com.android.builder.model.Variant;
import com.android.tools.lint.LintCliClient;
import com.android.tools.lint.LintCliFlags;
import com.android.tools.lint.Warning;
import com.android.tools.lint.client.api.IssueRegistry;
import com.android.tools.lint.client.api.LintRequest;
import com.android.tools.lint.detector.api.Issue;
import com.android.tools.lint.detector.api.Project;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Map;

public class LintGradleClient extends LintCliClient {
    private final AndroidProject mModelProject;
    private final String mVariantName;
    private final org.gradle.api.Project mGradleProject;
    private List<File> mCustomRules = Lists.newArrayList();
    private File mSdkHome;

    public LintGradleClient(@NonNull IssueRegistry registry, @NonNull LintCliFlags flags,
            @NonNull org.gradle.api.Project gradleProject, @NonNull AndroidProject modelProject,
            @Nullable File sdkHome, @Nullable String variantName) {
        super(flags);
        mGradleProject = gradleProject;
        mModelProject = modelProject;
        mVariantName = variantName;
        mSdkHome = sdkHome;
        mRegistry = registry;
    }

    public void setCustomRules(List<File> customRules) {
        mCustomRules = customRules;
    }

    @NonNull
    @Override
    public List<File> findRuleJars(@NonNull Project project) {
        return mCustomRules;
    }

    @NonNull
    @Override
    protected Project createProject(@NonNull File dir, @NonNull File referenceDir) {
        // Should not be called by lint since we supply an explicit set of projects
        // to the LintRequest
        throw new IllegalStateException();
    }

    @Override
    public File getSdkHome() {
        if (mSdkHome != null) {
            return mSdkHome;
        }
        return super.getSdkHome();
    }

    @Override
    @Nullable
    public File getCacheDir(boolean create) {
        File dir = new File(mGradleProject.getRootProject().getBuildDir(),
                FD_INTERMEDIATES + separator + "lint-cache"); //$NON-NLS-1$
        if (dir.exists() || create && dir.mkdirs()) {
            return dir;
        }

        return super.getCacheDir(create);
    }

    @Override
    @NonNull
    protected LintRequest createLintRequest(@NonNull List<File> files) {
        return new LintGradleRequest(this, mModelProject, mGradleProject, mVariantName, files);
    }

    /** Run lint with the given registry and return the resulting warnings */
    @NonNull
    public List<Warning> run(@NonNull IssueRegistry registry) throws IOException {
        run(registry, Collections.<File>emptyList());
        return mWarnings;
    }

    /**
     * Given a list of results from separate variants, merge them into a single
     * list of warnings, and mark their
     * @param warningMap a map from variant to corresponding warnings
     * @param project the project model
     * @return a merged list of issues
     */
    @NonNull
    public static List<Warning> merge(@NonNull Map<Variant, List<Warning>> warningMap,
            @NonNull AndroidProject project) {
        // Easy merge?
        if (warningMap.size() == 1) {
            return warningMap.values().iterator().next();
        }
        int maxCount = 0;
        for (List<Warning> warnings : warningMap.values()) {
            int size = warnings.size();
            maxCount = Math.max(size, maxCount);
        }
        if (maxCount == 0) {
            return Collections.emptyList();
        }

        int totalVariantCount = project.getVariants().size();

        List<Warning> merged = Lists.newArrayListWithExpectedSize(2 * maxCount);

        // Map fro issue to message to line number to file name to canonical warning
        Map<Issue, Map<String, Map<Integer, Map<String, Warning>>>> map = Maps
                .newHashMapWithExpectedSize(2 * maxCount);

        for (Map.Entry<Variant, List<Warning>> entry : warningMap.entrySet()) {
            Variant variant = entry.getKey();
            List<Warning> warnings = entry.getValue();
            for (Warning warning : warnings) {
                Map<String, Map<Integer, Map<String, Warning>>> messageMap = map.get(warning.issue);
                if (messageMap == null) {
                    messageMap = Maps.newHashMap();
                    map.put(warning.issue, messageMap);
                }
                Map<Integer, Map<String, Warning>> lineMap = messageMap.get(warning.message);
                if (lineMap == null) {
                    lineMap = Maps.newHashMap();
                    messageMap.put(warning.message, lineMap);
                }
                Map<String, Warning> fileMap = lineMap.get(warning.line);
                if (fileMap == null) {
                    fileMap = Maps.newHashMap();
                    lineMap.put(warning.line, fileMap);
                }
                String fileName = warning.file != null ? warning.file.getName() : "<unknown>";
                Warning canonical = fileMap.get(fileName);
                if (canonical == null) {
                    canonical = warning;
                    fileMap.put(fileName, canonical);
                    canonical.variants = Sets.newHashSet();
                    canonical.gradleProject = project;
                    merged.add(canonical);
                }
                canonical.variants.add(variant);
            }
        }

        // Clear out variants on any nodes that define all
        for (Warning warning : merged) {
            if (warning.variants != null && warning.variants.size() == totalVariantCount) {
                // If this error is present in all variants, just clear it out
                warning.variants = null;
            }

        }

        Collections.sort(merged);
        return merged;
    }

    @Override
    protected void addProgressPrinter() {
        // No progress printing from the Gradle lint task; gradle tasks
        // do not really do that, even for long-running jobs.
    }
}