153f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye/*
253f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye * Copyright (C) 2011 The Android Open Source Project
353f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye *
453f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye * Licensed under the Apache License, Version 2.0 (the "License");
553f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye * you may not use this file except in compliance with the License.
653f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye * You may obtain a copy of the License at
753f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye *
853f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye *      http://www.apache.org/licenses/LICENSE-2.0
953f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye *
1053f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye * Unless required by applicable law or agreed to in writing, software
1153f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye * distributed under the License is distributed on an "AS IS" BASIS,
1253f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1353f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye * See the License for the specific language governing permissions and
1453f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye * limitations under the License.
1553f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye */
1653f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye
1753f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbyepackage com.android.tools.lint.checks;
1853f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye
19af2ebe8bd69afb551b4182e401a0863a7f1ee0efTor Norbye
2012d4581faa6438941e65a9dc83213be34c6ca970Tor Norbyeimport static com.android.SdkConstants.ATTR_NAME;
2112d4581faa6438941e65a9dc83213be34c6ca970Tor Norbyeimport static com.android.SdkConstants.TAG_ARRAY;
2212d4581faa6438941e65a9dc83213be34c6ca970Tor Norbyeimport static com.android.SdkConstants.TAG_INTEGER_ARRAY;
2312d4581faa6438941e65a9dc83213be34c6ca970Tor Norbyeimport static com.android.SdkConstants.TAG_STRING_ARRAY;
2453f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye
257e4b8e9d595e45baa9d87cdb8282f02759e73abcTor Norbyeimport com.android.annotations.NonNull;
2653f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbyeimport com.android.resources.ResourceFolderType;
272b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbyeimport com.android.tools.lint.client.api.LintDriver;
28229581314076be1b6f82fe1efed2bd00da340899Tor Norbyeimport com.android.tools.lint.detector.api.Category;
2953f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbyeimport com.android.tools.lint.detector.api.Context;
3053f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbyeimport com.android.tools.lint.detector.api.Issue;
31229581314076be1b6f82fe1efed2bd00da340899Tor Norbyeimport com.android.tools.lint.detector.api.LintUtils;
3253f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbyeimport com.android.tools.lint.detector.api.Location;
3353f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbyeimport com.android.tools.lint.detector.api.ResourceXmlDetector;
3453f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbyeimport com.android.tools.lint.detector.api.Scope;
3553f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbyeimport com.android.tools.lint.detector.api.Severity;
363ce45b249f898697ae82e8c6dd045966227f3438Tor Norbyeimport com.android.tools.lint.detector.api.XmlContext;
3785e4a1a9dd133abb879ec211ce8dd385004edf22Xavier Ducrohetimport com.android.utils.Pair;
3853f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye
3953f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbyeimport org.w3c.dom.Attr;
4053f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbyeimport org.w3c.dom.Element;
412b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbyeimport org.w3c.dom.Node;
4253f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye
4353f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbyeimport java.io.File;
4453f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbyeimport java.util.ArrayList;
4553f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbyeimport java.util.Arrays;
4653f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbyeimport java.util.Collection;
4753f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbyeimport java.util.Collections;
4853f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbyeimport java.util.HashMap;
4953f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbyeimport java.util.HashSet;
5053f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbyeimport java.util.List;
5153f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbyeimport java.util.Map;
5253f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbyeimport java.util.Set;
5353f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye
5453f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye/**
5553f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye * Checks for arrays with inconsistent item counts
5653f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye */
5753f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbyepublic class ArraySizeDetector extends ResourceXmlDetector {
5853f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye
5953f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye    /** Are there differences in how many array elements are declared? */
6053f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye    public static final Issue INCONSISTENT = Issue.create(
6153f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye            "InconsistentArrays", //$NON-NLS-1$
6253f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye            "Checks for inconsistencies in the number of elements in arrays",
6353f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye            "When an array is translated in a different locale, it should normally have " +
6453f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye            "the same number of elements as the original array. When adding or removing " +
6553f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye            "elements to an array, it is easy to forget to update all the locales, and this " +
6653f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye            "lint warning finds inconsistencies like these.\n" +
6753f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye            "\n" +
6853f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye            "Note however that there may be cases where you really want to declare a " +
6953f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye            "different number of array items in each configuration (for example where " +
7053f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye            "the array represents available options, and those options differ for " +
7153f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye            "different layout orientations and so on), so use your own judgement to " +
7253f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye            "decide if this is really an error.\n" +
7353f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye            "\n" +
7453f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye            "You can suppress this error type if it finds false errors in your project.",
75229581314076be1b6f82fe1efed2bd00da340899Tor Norbye            Category.CORRECTNESS,
76229581314076be1b6f82fe1efed2bd00da340899Tor Norbye            7,
77229581314076be1b6f82fe1efed2bd00da340899Tor Norbye            Severity.WARNING,
78229581314076be1b6f82fe1efed2bd00da340899Tor Norbye            ArraySizeDetector.class,
79229581314076be1b6f82fe1efed2bd00da340899Tor Norbye            Scope.ALL_RESOURCES_SCOPE);
8053f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye
8153f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye    private Map<File, Pair<String, Integer>> mFileToArrayCount;
8253f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye
832b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye    /** Locations for each array name. Populated during phase 2, if necessary */
842b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye    private Map<String, Location> mLocations;
852b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye
862b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye    /** Error messages for each array name. Populated during phase 2, if necessary */
872b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye    private Map<String, String> mDescriptions;
882b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye
8953f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye    /** Constructs a new {@link ArraySizeDetector} */
9053f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye    public ArraySizeDetector() {
9153f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye    }
9253f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye
9353f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye    @Override
947e4b8e9d595e45baa9d87cdb8282f02759e73abcTor Norbye    public boolean appliesTo(@NonNull ResourceFolderType folderType) {
9553f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye        return folderType == ResourceFolderType.VALUES;
9653f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye    }
9753f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye
9853f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye    @Override
9953f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye    public Collection<String> getApplicableElements() {
100b45957a134d6fd6184348387fd0f0b14ffa7021cTor Norbye        return Arrays.asList(
10153f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye                TAG_ARRAY,
10253f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye                TAG_STRING_ARRAY,
10353f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye                TAG_INTEGER_ARRAY
104b45957a134d6fd6184348387fd0f0b14ffa7021cTor Norbye        );
10553f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye    }
10653f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye
10753f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye    @Override
1087e4b8e9d595e45baa9d87cdb8282f02759e73abcTor Norbye    public void beforeCheckProject(@NonNull Context context) {
1092b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye        if (context.getPhase() == 1) {
1102b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye            mFileToArrayCount = new HashMap<File, Pair<String,Integer>>(30);
1112b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye        }
11253f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye    }
11353f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye
11453f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye    @Override
1157e4b8e9d595e45baa9d87cdb8282f02759e73abcTor Norbye    public void afterCheckProject(@NonNull Context context) {
1162b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye        if (context.getPhase() == 1) {
1172b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye            // Check that all arrays for the same name have the same number of translations
1182b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye
1192b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye            Set<String> alreadyReported = new HashSet<String>();
1202b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye            Map<String, Integer> countMap = new HashMap<String, Integer>();
1212b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye            Map<String, File> fileMap = new HashMap<String, File>();
1222b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye
1232b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye            // Process the file in sorted file order to ensure stable output
1242b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye            List<File> keys = new ArrayList<File>(mFileToArrayCount.keySet());
1252b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye            Collections.sort(keys);
12653f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye
1272b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye            for (File file : keys) {
1282b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                Pair<String, Integer> pair = mFileToArrayCount.get(file);
1292b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                String name = pair.getFirst();
1302b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                if (alreadyReported.contains(name)) {
1312b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    continue;
1322b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                }
1332b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                Integer count = pair.getSecond();
13453f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye
1352b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                Integer current = countMap.get(name);
1362b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                if (current == null) {
1372b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    countMap.put(name, count);
1382b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    fileMap.put(name, file);
1392b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                } else if (!count.equals(current)) {
1402b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    alreadyReported.add(name);
14153f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye
1422b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    if (mLocations == null) {
1432b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                        mLocations = new HashMap<String, Location>();
1442b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                        mDescriptions = new HashMap<String, String>();
1452b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    }
1462b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    mLocations.put(name, null);
1472b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye
1482b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    String thisName = file.getParentFile().getName() + File.separator
1492b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                            + file.getName();
1502b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    File otherFile = fileMap.get(name);
1512b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    String otherName = otherFile.getParentFile().getName() + File.separator
1522b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                            + otherFile.getName();
1532b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    String message = String.format(
1542b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                         "Array %1$s has an inconsistent number of items (%2$d in %3$s, %4$d in %5$s)",
1552b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                         name, count, thisName, current, otherName);
1562b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                     mDescriptions.put(name,  message);
1572b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                }
15853f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye            }
1592b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye
1602b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye            if (mLocations != null) {
1612b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                // Request another scan through the resources such that we can
1622b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                // gather the actual locations
1632b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                context.getDriver().requestRepeat(this, Scope.ALL_RESOURCES_SCOPE);
16453f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye            }
1652b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye            mFileToArrayCount = null;
1662b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye        } else {
1672b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye            if (mLocations != null) {
1682b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                List<String> names = new ArrayList<String>(mLocations.keySet());
1692b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                Collections.sort(names);
1702b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                for (String name : names) {
1712b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    Location location = mLocations.get(name);
1722b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    // We were prepending locations, but we want to prefer the base folders
1732b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    location = Location.reverse(location);
17453f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye
1752b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    // Make sure we still have a conflict, in case one or more of the
1762b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    // elements were marked with tools:ignore
1772b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    int count = -1;
1782b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    Location curr = location;
1792b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    LintDriver driver = context.getDriver();
1802b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    boolean foundConflict = false;
1812b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    for (curr = location; curr != null; curr = curr.getSecondary()) {
1822b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                        Object clientData = curr.getClientData();
1832b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                        if (clientData instanceof Node) {
1842b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                            Node node = (Node) clientData;
1852b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                            if (driver.isSuppressed(INCONSISTENT, node)) {
1862b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                                continue;
1872b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                            }
1882b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                            int newCount = LintUtils.getChildCount(node);
1892b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                            if (newCount != count) {
1902b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                                if (count == -1) {
1912b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                                    count = newCount; // first number encountered
1922b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                                } else {
1932b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                                    foundConflict = true;
1942b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                                    break;
1952b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                                }
1962b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                            }
1972b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                        } else {
1982b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                            foundConflict = true;
1992b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                            break;
2002b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                        }
2012b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    }
2022b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye
2032b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    // Through one or more tools:ignore, there is no more conflict so
2042b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    // ignore this element
2052b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    if (!foundConflict) {
2062b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                        continue;
2072b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    }
2082b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye
2092b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    String message = mDescriptions.get(name);
2102b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    context.report(INCONSISTENT, location, message, null);
2112b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                }
2122b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye            }
2132b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye
2142b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye            mLocations = null;
2152b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye            mDescriptions = null;
2162b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye        }
21753f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye    }
21853f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye
21953f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye    @Override
2207e4b8e9d595e45baa9d87cdb8282f02759e73abcTor Norbye    public void visitElement(@NonNull XmlContext context, @NonNull Element element) {
2212b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye        int phase = context.getPhase();
2222b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye
22353f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye        Attr attribute = element.getAttributeNode(ATTR_NAME);
22453f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye        if (attribute == null || attribute.getValue().length() == 0) {
2252b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye            if (phase != 1) {
2262b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                return;
2272b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye            }
22869067f399231dc28f4ff0aa02b60153ffd2d5831Tor Norbye            context.report(INCONSISTENT, element, context.getLocation(element),
22953f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye                String.format("Missing name attribute in %1$s declaration", element.getTagName()),
23053f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye                null);
23153f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye        } else {
23253f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye            String name = attribute.getValue();
2332b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye            if (phase == 1) {
2342b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                int childCount = LintUtils.getChildCount(element);
2352b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                mFileToArrayCount.put(context.file, Pair.of(name, childCount));
2362b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye            } else {
2372b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                assert phase == 2;
2382b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                if (mLocations.containsKey(name)) {
2392b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    if (context.getDriver().isSuppressed(INCONSISTENT, element)) {
2402b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                        return;
2412b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    }
2422b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    Location location = context.getLocation(element);
2432b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    location.setClientData(element);
2442b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    location.setMessage(String.format("Declaration with array size (%1$d)",
2452b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                                    LintUtils.getChildCount(element)));
2462b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    location.setSecondary(mLocations.get(name));
2472b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    mLocations.put(name, location);
2482b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                }
2492b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye            }
25053f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye        }
25153f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye    }
25253f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye}
253