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

com.android.tools.lint.checks.LintInspectionBridge Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2016 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.tools.lint.checks;

import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
import com.android.builder.model.AndroidLibrary;
import com.android.builder.model.Dependencies;
import com.android.builder.model.JavaLibrary;
import com.android.builder.model.Library;
import com.android.builder.model.MavenCoordinates;
import com.android.tools.lint.client.api.JavaEvaluator;
import com.android.tools.lint.detector.api.Issue;
import com.google.common.collect.Maps;
import com.intellij.psi.PsiElement;
import java.io.File;
import java.util.Collection;
import java.util.Map;
import org.jetbrains.annotations.NotNull;

/**
 * Interface implemented by some lint checks which need to bridge to
 * IDE inspections. This lets these issues be reported from IDE inspections
 * that do not run as part of lint (with access to lint's contexts, projects, etc)
 * without duplicating the logic of the check on the IDE side. See
 * the ResourceTypeInspection in the IDE.
 */
public abstract class LintInspectionBridge {
    /**
     * Report the given issue
     */
    public abstract void report(@NonNull Issue issue,
      @NonNull PsiElement locationNode,
      @NonNull PsiElement scopeNode,
      @NonNull String message);

    public abstract boolean isTestSource();

    @Nullable
    public abstract Dependencies getDependencies();

    /**
     * Return the Gradle group id for the given element, if applicable. For example, for
     * a method in the appcompat library, this would return "com.android.support".
     */
    @Nullable
    public MavenCoordinates getLibrary(@NonNull PsiElement element) {
        String jarFile = getEvaluator().findJarPath(element);
        if (jarFile != null) {
            if (jarToGroup == null) {
                jarToGroup = Maps.newHashMap();
            }
            MavenCoordinates coordinates = jarToGroup.get(jarFile);
            if (coordinates == null) {
                Library library = findOwnerLibrary(jarFile);
                if (library != null) {
                    coordinates = library.getResolvedCoordinates();
                }
                if (coordinates == null) {
                    // Use string location to figure it out. Note however that
                    // this doesn't work when the build cache is in effect.
                    // Example:
                    // $PROJECT_DIRECTORY/app/build/intermediates/exploded-aar/com.android.support/
                    //          /appcompat-v7/25.0.0-SNAPSHOT/jars/classes.jar
                    // and we want to pick out "com.android.support" and "appcompat-v7"
                    int index = jarFile.indexOf("exploded-aar");
                    if (index != -1) {
                        index += 13; // "exploded-aar/".length()
                        for (int i = index; i < jarFile.length(); i++) {
                            char c = jarFile.charAt(i);
                            if (c == '/' || c == File.separatorChar) {
                                String groupId = jarFile.substring(index, i);
                                i++;
                                for (int j = i; j < jarFile.length(); j++) {
                                    c = jarFile.charAt(j);
                                    if (c == '/' || c == File.separatorChar) {
                                        String artifactId = jarFile.substring(i, j);
                                        coordinates = new MyMavenCoordinates(groupId, artifactId);
                                        break;
                                    }
                                }
                                break;
                            }
                        }
                    }
                }
                if (coordinates == null) {
                    coordinates = MyMavenCoordinates.NONE;
                }
                jarToGroup.put(jarFile, coordinates);
            }
            return coordinates == MyMavenCoordinates.NONE ? null : coordinates;
        }

        return null;
    }

    @Nullable
    public Library findOwnerLibrary(@NonNull String jarFile) {
        Dependencies dependencies = getDependencies();
        if (dependencies != null) {
            Library match = findOwnerLibrary(dependencies.getLibraries(), jarFile);
            if (match != null) {
                return match;
            }
            match = findOwnerJavaLibrary(dependencies.getJavaLibraries(), jarFile);
            if (match != null) {
                return match;
            }
        }

        return null;
    }

    @Nullable
    private static Library findOwnerJavaLibrary(
            @NonNull Collection dependencies,
            @NonNull String jarFile) {
        for (JavaLibrary library : dependencies) {
            if (jarFile.equals(library.getJarFile().getPath())) {
                return library;
            }
            Library match = findOwnerJavaLibrary(library.getDependencies(), jarFile);
            if (match != null) {
                return match;
            }
        }

        return null;
    }

    @Nullable
    private static Library findOwnerLibrary(
            @NonNull Collection dependencies,
            @NonNull String jarFile) {
        for (AndroidLibrary library : dependencies) {
            if (jarFile.equals(library.getJarFile().getPath())) {
                return library;
            }
            for (File jar : library.getLocalJars()) {
                if (jarFile.equals(jar.getPath())) {
                    return library;
                }
            }
            Library match = findOwnerLibrary(library.getLibraryDependencies(), jarFile);
            if (match != null) {
                return match;
            }

            match = findOwnerJavaLibrary(library.getJavaDependencies(), jarFile);
            if (match != null) {
                return match;
            }
        }

        return null;
    }

    @NonNull
    public abstract JavaEvaluator getEvaluator();

    /** Cache for {@link #getLibrary(PsiElement)} */
    private Map jarToGroup;

    /**
     * Dummy implementation of {@link com.android.builder.model.MavenCoordinates} which
     * only stores group and artifact id's for now
     */
    private static class MyMavenCoordinates implements MavenCoordinates {
        private static final MyMavenCoordinates NONE = new MyMavenCoordinates("", "");

        private final String groupId;
        private final String artifactId;

        public MyMavenCoordinates(@NonNull String groupId, @NonNull String artifactId) {
            this.groupId = groupId;
            this.artifactId = artifactId;
        }

        @NonNull
        @Override
        public String getGroupId() {
            return groupId;
        }

        @NonNull
        @Override
        public String getArtifactId() {
            return artifactId;
        }

        @NonNull
        @Override
        public String getVersion() {
            return "";
        }

        @NonNull
        @Override
        public String getPackaging() {
            return "";
        }

        @Nullable
        @Override
        public String getClassifier() {
            return "";
        }

        @Override
        public String getVersionlessId() {
            return groupId + ':' + artifactId;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy