Search in sources :

Example 6 with Project

use of com.android.tools.klint.detector.api.Project in project kotlin by JetBrains.

the class IntellijLintProject method findAndroidModule.

/** Find an Android module that depends on this module; prefer app modules over library modules */
@Nullable
private static Module findAndroidModule(@NonNull final Module module) {
    // Search for dependencies of this module
    Graph<Module> graph = ApplicationManager.getApplication().runReadAction(new Computable<Graph<Module>>() {

        @Override
        public Graph<Module> compute() {
            com.intellij.openapi.project.Project project = module.getProject();
            if (project.isDisposed()) {
                return null;
            }
            return ModuleManager.getInstance(project).moduleGraph();
        }
    });
    if (graph == null) {
        return null;
    }
    Set<AndroidFacet> facets = Sets.newHashSet();
    HashSet<Module> seen = Sets.newHashSet();
    seen.add(module);
    addAndroidModules(facets, seen, graph, module);
    // Prefer Android app modules
    for (AndroidFacet facet : facets) {
        if (!facet.isLibraryProject()) {
            return facet.getModule();
        }
    }
    // Resort to library modules if no app module depends directly on it
    if (!facets.isEmpty()) {
        return facets.iterator().next().getModule();
    }
    return null;
}
Also used : Project(com.android.tools.klint.detector.api.Project) Graph(com.intellij.util.graph.Graph) Module(com.intellij.openapi.module.Module) AndroidFacet(org.jetbrains.android.facet.AndroidFacet) Nullable(org.jetbrains.annotations.Nullable)

Example 7 with Project

use of com.android.tools.klint.detector.api.Project in project kotlin by JetBrains.

the class OverdrawDetector method getTheme.

/** Return the theme to be used for the given layout */
private String getTheme(Context context, String layoutName) {
    if (mActivityToTheme != null && mLayoutToActivity != null) {
        List<String> activities = mLayoutToActivity.get(layoutName);
        if (activities != null) {
            for (String activity : activities) {
                String theme = mActivityToTheme.get(activity);
                if (theme != null) {
                    return theme;
                }
            }
        }
    }
    if (mManifestTheme != null) {
        return mManifestTheme;
    }
    Project project = context.getMainProject();
    int apiLevel = project.getTargetSdk();
    if (apiLevel == -1) {
        apiLevel = project.getMinSdk();
    }
    if (apiLevel >= 11) {
        //$NON-NLS-1$
        return "@android:style/Theme.Holo";
    } else {
        //$NON-NLS-1$
        return "@android:style/Theme";
    }
}
Also used : Project(com.android.tools.klint.detector.api.Project)

Example 8 with Project

use of com.android.tools.klint.detector.api.Project in project kotlin by JetBrains.

the class LayoutInflationDetector method hasLayoutParams.

private static boolean hasLayoutParams(@NonNull JavaContext context, String name) {
    LintClient client = context.getClient();
    if (!client.supportsProjectResources()) {
        // not certain
        return true;
    }
    Project project = context.getProject();
    AbstractResourceRepository resources = client.getProjectResources(project, true);
    if (resources == null) {
        // not certain
        return true;
    }
    List<ResourceItem> items = resources.getResourceItem(ResourceType.LAYOUT, name);
    if (items == null || items.isEmpty()) {
        return false;
    }
    for (ResourceItem item : items) {
        ResourceFile source = item.getSource();
        if (source == null) {
            // not certain
            return true;
        }
        File file = source.getFile();
        if (file.exists()) {
            try {
                String s = context.getClient().readFile(file);
                if (hasLayoutParams(new StringReader(s))) {
                    return true;
                }
            } catch (Exception e) {
                context.log(e, "Could not read/parse inflated layout");
                // not certain
                return true;
            }
        }
    }
    return false;
}
Also used : Project(com.android.tools.klint.detector.api.Project) ResourceFile(com.android.ide.common.res2.ResourceFile) AbstractResourceRepository(com.android.ide.common.res2.AbstractResourceRepository) LintClient(com.android.tools.klint.client.api.LintClient) StringReader(java.io.StringReader) ResourceItem(com.android.ide.common.res2.ResourceItem) File(java.io.File) ResourceFile(com.android.ide.common.res2.ResourceFile) IOException(java.io.IOException) XmlPullParserException(org.xmlpull.v1.XmlPullParserException)

Example 9 with Project

use of com.android.tools.klint.detector.api.Project in project kotlin by JetBrains.

the class AppIndexingApiDetector method replaceUrlWithValue.

private static String replaceUrlWithValue(@NonNull XmlContext context, @NonNull String str) {
    Project project = context.getProject();
    LintClient client = context.getClient();
    if (!client.supportsProjectResources()) {
        return str;
    }
    ResourceUrl style = ResourceUrl.parse(str);
    if (style == null || style.type != ResourceType.STRING || style.framework) {
        return str;
    }
    AbstractResourceRepository resources = client.getProjectResources(project, true);
    if (resources == null) {
        return str;
    }
    List<ResourceItem> items = resources.getResourceItem(ResourceType.STRING, style.name);
    if (items == null || items.isEmpty()) {
        return str;
    }
    ResourceValue resourceValue = items.get(0).getResourceValue(false);
    if (resourceValue == null) {
        return str;
    }
    return resourceValue.getValue() == null ? str : resourceValue.getValue();
}
Also used : Project(com.android.tools.klint.detector.api.Project) AbstractResourceRepository(com.android.ide.common.res2.AbstractResourceRepository) LintClient(com.android.tools.klint.client.api.LintClient) ResourceValue(com.android.ide.common.rendering.api.ResourceValue) ResourceItem(com.android.ide.common.res2.ResourceItem) ResourceUrl(com.android.ide.common.resources.ResourceUrl)

Example 10 with Project

use of com.android.tools.klint.detector.api.Project in project kotlin by JetBrains.

the class RtlDetector method visitAttribute.

@Override
public void visitAttribute(@NonNull XmlContext context, @NonNull Attr attribute) {
    Project project = context.getMainProject();
    String value = attribute.getValue();
    if (!ANDROID_URI.equals(attribute.getNamespaceURI())) {
        // the MissingPrefixDetector)
        return;
    }
    String name = attribute.getLocalName();
    assert name != null : attribute.getName();
    if (name.equals(ATTR_SUPPORTS_RTL)) {
        mEnabledRtlSupport = Boolean.valueOf(value);
        if (!attribute.getOwnerElement().getTagName().equals(TAG_APPLICATION)) {
            context.report(ENABLED, attribute, context.getLocation(attribute), String.format("Wrong declaration: `%1$s` should be defined on the `<application>` element", attribute.getName()));
        }
        int targetSdk = project.getTargetSdk();
        if (mEnabledRtlSupport && targetSdk < RTL_API) {
            String message = String.format("You must set `android:targetSdkVersion` to at least %1$d when " + "enabling RTL support (is %2$d)", RTL_API, project.getTargetSdk());
            context.report(ENABLED, attribute, context.getValueLocation(attribute), message);
        }
        return;
    }
    if (!rtlApplies(context)) {
        return;
    }
    if (name.equals(ATTR_TEXT_ALIGNMENT)) {
        if (context.getProject().getReportIssues()) {
            mUsesRtlAttributes = true;
        }
        Element element = attribute.getOwnerElement();
        final String gravity;
        final Attr gravityNode;
        if (element.hasAttributeNS(ANDROID_URI, ATTR_GRAVITY)) {
            gravityNode = element.getAttributeNodeNS(ANDROID_URI, ATTR_GRAVITY);
            gravity = gravityNode.getValue();
        } else if (element.hasAttributeNS(ANDROID_URI, ATTR_LAYOUT_GRAVITY)) {
            gravityNode = element.getAttributeNodeNS(ANDROID_URI, ATTR_LAYOUT_GRAVITY);
            gravity = gravityNode.getValue();
        } else if (project.getMinSdk() < RTL_API) {
            int folderVersion = context.getFolderVersion();
            if (folderVersion < RTL_API && context.isEnabled(COMPAT)) {
                String expectedGravity = getTextAlignmentToGravity(value);
                if (expectedGravity != null) {
                    String message = String.format("To support older versions than API 17 (project specifies %1$d) " + "you must *also* specify `gravity` or `layout_gravity=\"%2$s\"`", project.getMinSdk(), expectedGravity);
                    context.report(COMPAT, attribute, context.getNameLocation(attribute), message);
                }
            }
            return;
        } else {
            return;
        }
        String expectedGravity = getTextAlignmentToGravity(value);
        if (expectedGravity != null && !gravity.contains(expectedGravity) && context.isEnabled(COMPAT)) {
            String message = String.format("Inconsistent alignment specification between " + "`textAlignment` and `gravity` attributes: was `%1$s`, expected `%2$s`", gravity, expectedGravity);
            Location location = context.getValueLocation(attribute);
            context.report(COMPAT, attribute, location, message);
            Location secondary = context.getValueLocation(gravityNode);
            secondary.setMessage("Incompatible direction here");
            location.setSecondary(secondary);
        }
        return;
    }
    if (name.equals(ATTR_GRAVITY) || name.equals(ATTR_LAYOUT_GRAVITY)) {
        boolean isLeft = value.contains(GRAVITY_VALUE_LEFT);
        boolean isRight = value.contains(GRAVITY_VALUE_RIGHT);
        if (!isLeft && !isRight) {
            if ((value.contains(GRAVITY_VALUE_START) || value.contains(GRAVITY_VALUE_END)) && context.getProject().getReportIssues()) {
                mUsesRtlAttributes = true;
            }
            return;
        }
        String message = String.format("Use \"`%1$s`\" instead of \"`%2$s`\" to ensure correct behavior in " + "right-to-left locales", isLeft ? GRAVITY_VALUE_START : GRAVITY_VALUE_END, isLeft ? GRAVITY_VALUE_LEFT : GRAVITY_VALUE_RIGHT);
        if (context.isEnabled(USE_START)) {
            context.report(USE_START, attribute, context.getValueLocation(attribute), message);
        }
        return;
    }
    // Some other left/right/start/end attribute
    int targetSdk = project.getTargetSdk();
    // TODO: If attribute is drawableLeft or drawableRight, add note that you might
    // want to consider adding a specialized image in the -ldrtl folder as well
    Element element = attribute.getOwnerElement();
    boolean isPaddingAttribute = isPaddingAttribute(name);
    if (isPaddingAttribute || isMarginAttribute(name)) {
        String opposite = convertToOppositeDirection(name);
        if (element.hasAttributeNS(ANDROID_URI, opposite)) {
            String oldValue = element.getAttributeNS(ANDROID_URI, opposite);
            if (value.equals(oldValue)) {
                return;
            }
        } else if (isPaddingAttribute && !element.hasAttributeNS(ANDROID_URI, isOldAttribute(opposite) ? convertOldToNew(opposite) : convertNewToOld(opposite)) && context.isEnabled(SYMMETRY)) {
            String message = String.format("When you define `%1$s` you should probably also define `%2$s` for " + "right-to-left symmetry", name, opposite);
            context.report(SYMMETRY, attribute, context.getNameLocation(attribute), message);
        }
    }
    boolean isOld = isOldAttribute(name);
    if (isOld) {
        if (!context.isEnabled(USE_START)) {
            return;
        }
        String rtl = convertOldToNew(name);
        if (element.hasAttributeNS(ANDROID_URI, rtl)) {
            if (project.getMinSdk() >= RTL_API || context.getFolderVersion() >= RTL_API) {
                // Warn that left/right isn't needed
                String message = String.format("Redundant attribute `%1$s`; already defining `%2$s` with " + "`targetSdkVersion` %3$s", name, rtl, targetSdk);
                context.report(USE_START, attribute, context.getNameLocation(attribute), message);
            }
        } else {
            String message;
            if (project.getMinSdk() >= RTL_API || context.getFolderVersion() >= RTL_API) {
                message = String.format("Consider replacing `%1$s` with `%2$s:%3$s=\"%4$s\"` to better support " + "right-to-left layouts", attribute.getName(), attribute.getPrefix(), rtl, value);
            } else {
                message = String.format("Consider adding `%1$s:%2$s=\"%3$s\"` to better support " + "right-to-left layouts", attribute.getPrefix(), rtl, value);
            }
            context.report(USE_START, attribute, context.getNameLocation(attribute), message);
        }
    } else {
        if (project.getMinSdk() >= RTL_API || !context.isEnabled(COMPAT)) {
            // Only supporting 17+: no need to define older attributes
            return;
        }
        int folderVersion = context.getFolderVersion();
        if (folderVersion >= RTL_API) {
            // In a -v17 folder or higher: no need to define older attributes
            return;
        }
        String old = convertNewToOld(name);
        if (element.hasAttributeNS(ANDROID_URI, old)) {
            return;
        }
        String message = String.format("To support older versions than API 17 (project specifies %1$d) " + "you should *also* add `%2$s:%3$s=\"%4$s\"`", project.getMinSdk(), attribute.getPrefix(), old, convertNewToOld(value));
        context.report(COMPAT, attribute, context.getNameLocation(attribute), message);
    }
}
Also used : Project(com.android.tools.klint.detector.api.Project) UElement(org.jetbrains.uast.UElement) PsiElement(com.intellij.psi.PsiElement) Element(org.w3c.dom.Element) Attr(org.w3c.dom.Attr) Location(com.android.tools.klint.detector.api.Location)

Aggregations

Project (com.android.tools.klint.detector.api.Project)17 File (java.io.File)8 PsiFile (com.intellij.psi.PsiFile)4 IOException (java.io.IOException)4 NonNull (com.android.annotations.NonNull)3 Module (com.intellij.openapi.module.Module)3 AbstractResourceRepository (com.android.ide.common.res2.AbstractResourceRepository)2 ResourceItem (com.android.ide.common.res2.ResourceItem)2 LintClient (com.android.tools.klint.client.api.LintClient)2 ClassContext (com.android.tools.klint.detector.api.ClassContext)2 Context (com.android.tools.klint.detector.api.Context)2 JavaContext (com.android.tools.klint.detector.api.JavaContext)2 Location (com.android.tools.klint.detector.api.Location)2 ResourceContext (com.android.tools.klint.detector.api.ResourceContext)2 XmlContext (com.android.tools.klint.detector.api.XmlContext)2 HashSet (java.util.HashSet)2 AndroidFacet (org.jetbrains.android.facet.AndroidFacet)2 ResourceValue (com.android.ide.common.rendering.api.ResourceValue)1 ResourceFile (com.android.ide.common.res2.ResourceFile)1 ResourceUrl (com.android.ide.common.resources.ResourceUrl)1