ArraySizeDetector.java revision 2b0b5b7e6b2886d6c21355d9713ca2596a92e219
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
20af2ebe8bd69afb551b4182e401a0863a7f1ee0efTor Norbyeimport static com.android.tools.lint.detector.api.LintConstants.ATTR_NAME;
21af2ebe8bd69afb551b4182e401a0863a7f1ee0efTor Norbyeimport static com.android.tools.lint.detector.api.LintConstants.TAG_ARRAY;
22af2ebe8bd69afb551b4182e401a0863a7f1ee0efTor Norbyeimport static com.android.tools.lint.detector.api.LintConstants.TAG_INTEGER_ARRAY;
23af2ebe8bd69afb551b4182e401a0863a7f1ee0efTor Norbyeimport static com.android.tools.lint.detector.api.LintConstants.TAG_STRING_ARRAY;
2453f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye
2553f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbyeimport com.android.resources.ResourceFolderType;
262b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbyeimport com.android.tools.lint.client.api.LintDriver;
27229581314076be1b6f82fe1efed2bd00da340899Tor Norbyeimport com.android.tools.lint.detector.api.Category;
2853f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbyeimport com.android.tools.lint.detector.api.Context;
2953f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbyeimport com.android.tools.lint.detector.api.Issue;
30229581314076be1b6f82fe1efed2bd00da340899Tor Norbyeimport com.android.tools.lint.detector.api.LintUtils;
3153f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbyeimport com.android.tools.lint.detector.api.Location;
3253f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbyeimport com.android.tools.lint.detector.api.ResourceXmlDetector;
3353f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbyeimport com.android.tools.lint.detector.api.Scope;
3453f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbyeimport com.android.tools.lint.detector.api.Severity;
3553f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbyeimport com.android.tools.lint.detector.api.Speed;
363ce45b249f898697ae82e8c6dd045966227f3438Tor Norbyeimport com.android.tools.lint.detector.api.XmlContext;
3753f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbyeimport com.android.util.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
9453f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye    public boolean appliesTo(ResourceFolderType folderType) {
9553f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye        return folderType == ResourceFolderType.VALUES;
9653f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye    }
9753f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye
9853f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye    @Override
9953f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye    public Speed getSpeed() {
10053f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye        return Speed.NORMAL;
10153f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye    }
10253f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye
10353f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye    @Override
10453f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye    public Collection<String> getApplicableElements() {
105b45957a134d6fd6184348387fd0f0b14ffa7021cTor Norbye        return Arrays.asList(
10653f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye                TAG_ARRAY,
10753f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye                TAG_STRING_ARRAY,
10853f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye                TAG_INTEGER_ARRAY
109b45957a134d6fd6184348387fd0f0b14ffa7021cTor Norbye        );
11053f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye    }
11153f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye
11253f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye    @Override
11353f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye    public void beforeCheckProject(Context context) {
1142b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye        if (context.getPhase() == 1) {
1152b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye            mFileToArrayCount = new HashMap<File, Pair<String,Integer>>(30);
1162b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye        }
11753f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye    }
11853f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye
11953f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye    @Override
12053f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye    public void afterCheckProject(Context context) {
1212b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye        if (context.getPhase() == 1) {
1222b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye            // Check that all arrays for the same name have the same number of translations
1232b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye
1242b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye            Set<String> alreadyReported = new HashSet<String>();
1252b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye            Map<String, Integer> countMap = new HashMap<String, Integer>();
1262b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye            Map<String, File> fileMap = new HashMap<String, File>();
1272b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye
1282b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye            // Process the file in sorted file order to ensure stable output
1292b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye            List<File> keys = new ArrayList<File>(mFileToArrayCount.keySet());
1302b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye            Collections.sort(keys);
13153f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye
1322b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye            for (File file : keys) {
1332b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                Pair<String, Integer> pair = mFileToArrayCount.get(file);
1342b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                String name = pair.getFirst();
1352b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                if (alreadyReported.contains(name)) {
1362b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    continue;
1372b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                }
1382b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                Integer count = pair.getSecond();
13953f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye
1402b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                Integer current = countMap.get(name);
1412b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                if (current == null) {
1422b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    countMap.put(name, count);
1432b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    fileMap.put(name, file);
1442b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                } else if (!count.equals(current)) {
1452b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    alreadyReported.add(name);
14653f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye
1472b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    if (mLocations == null) {
1482b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                        mLocations = new HashMap<String, Location>();
1492b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                        mDescriptions = new HashMap<String, String>();
1502b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    }
1512b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    mLocations.put(name, null);
1522b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye
1532b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    String thisName = file.getParentFile().getName() + File.separator
1542b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                            + file.getName();
1552b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    File otherFile = fileMap.get(name);
1562b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    String otherName = otherFile.getParentFile().getName() + File.separator
1572b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                            + otherFile.getName();
1582b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    String message = String.format(
1592b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                         "Array %1$s has an inconsistent number of items (%2$d in %3$s, %4$d in %5$s)",
1602b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                         name, count, thisName, current, otherName);
1612b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                     mDescriptions.put(name,  message);
1622b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                }
16353f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye            }
1642b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye
1652b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye            if (mLocations != null) {
1662b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                // Request another scan through the resources such that we can
1672b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                // gather the actual locations
1682b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                context.getDriver().requestRepeat(this, Scope.ALL_RESOURCES_SCOPE);
16953f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye            }
1702b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye            mFileToArrayCount = null;
1712b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye        } else {
1722b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye            if (mLocations != null) {
1732b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                List<String> names = new ArrayList<String>(mLocations.keySet());
1742b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                Collections.sort(names);
1752b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                for (String name : names) {
1762b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    Location location = mLocations.get(name);
1772b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    // We were prepending locations, but we want to prefer the base folders
1782b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    location = Location.reverse(location);
17953f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye
1802b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    // Make sure we still have a conflict, in case one or more of the
1812b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    // elements were marked with tools:ignore
1822b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    int count = -1;
1832b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    Location curr = location;
1842b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    LintDriver driver = context.getDriver();
1852b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    boolean foundConflict = false;
1862b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    for (curr = location; curr != null; curr = curr.getSecondary()) {
1872b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                        Object clientData = curr.getClientData();
1882b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                        if (clientData instanceof Node) {
1892b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                            Node node = (Node) clientData;
1902b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                            if (driver.isSuppressed(INCONSISTENT, node)) {
1912b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                                continue;
1922b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                            }
1932b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                            int newCount = LintUtils.getChildCount(node);
1942b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                            if (newCount != count) {
1952b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                                if (count == -1) {
1962b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                                    count = newCount; // first number encountered
1972b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                                } else {
1982b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                                    foundConflict = true;
1992b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                                    break;
2002b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                                }
2012b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                            }
2022b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                        } else {
2032b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                            foundConflict = true;
2042b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                            break;
2052b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                        }
2062b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    }
2072b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye
2082b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    // Through one or more tools:ignore, there is no more conflict so
2092b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    // ignore this element
2102b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    if (!foundConflict) {
2112b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                        continue;
2122b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    }
2132b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye
2142b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    String message = mDescriptions.get(name);
2152b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    context.report(INCONSISTENT, location, message, null);
2162b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                }
2172b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye            }
2182b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye
2192b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye            mLocations = null;
2202b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye            mDescriptions = null;
2212b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye        }
22253f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye    }
22353f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye
22453f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye    @Override
2253ce45b249f898697ae82e8c6dd045966227f3438Tor Norbye    public void visitElement(XmlContext context, Element element) {
2262b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye        int phase = context.getPhase();
2272b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye
22853f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye        Attr attribute = element.getAttributeNode(ATTR_NAME);
22953f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye        if (attribute == null || attribute.getValue().length() == 0) {
2302b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye            if (phase != 1) {
2312b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                return;
2322b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye            }
23369067f399231dc28f4ff0aa02b60153ffd2d5831Tor Norbye            context.report(INCONSISTENT, element, context.getLocation(element),
23453f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye                String.format("Missing name attribute in %1$s declaration", element.getTagName()),
23553f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye                null);
23653f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye        } else {
23753f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye            String name = attribute.getValue();
2382b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye            if (phase == 1) {
2392b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                int childCount = LintUtils.getChildCount(element);
2402b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                mFileToArrayCount.put(context.file, Pair.of(name, childCount));
2412b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye            } else {
2422b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                assert phase == 2;
2432b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                if (mLocations.containsKey(name)) {
2442b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    if (context.getDriver().isSuppressed(INCONSISTENT, element)) {
2452b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                        return;
2462b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    }
2472b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    Location location = context.getLocation(element);
2482b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    location.setClientData(element);
2492b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    location.setMessage(String.format("Declaration with array size (%1$d)",
2502b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                                    LintUtils.getChildCount(element)));
2512b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    location.setSecondary(mLocations.get(name));
2522b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                    mLocations.put(name, location);
2532b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye                }
2542b0b5b7e6b2886d6c21355d9713ca2596a92e219Tor Norbye            }
25553f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye        }
25653f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye    }
25753f27f8adbe5a657e766d81af1d584c2490730b7Tor Norbye}
258