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