Package com.android.tools.lint.detector.api.Location

Examples of com.android.tools.lint.detector.api.Location.Handle


        // Check to make sure that the argument counts and types are consistent
        int prevCount = -1;
        for (Pair<Handle, String> pair : list) {
            Set<Integer> indices = new HashSet<Integer>();
            int count = getFormatArgumentCount(pair.getSecond(), indices);
            Handle handle = pair.getFirst();
            if (prevCount != -1 && prevCount != count) {
                Object clientData = handle.getClientData();
                if (clientData instanceof Node) {
                    if (context.getDriver().isSuppressed(null, ARG_COUNT, (Node) clientData)) {
                        return;
                    }
                }
                Location location = handle.resolve();
                Location secondary = list.get(0).getFirst().resolve();
                secondary.setMessage("Conflicting number of arguments here");
                location.setSecondary(secondary);
                String message = String.format(
                        "Inconsistent number of arguments in formatting string %1$s; " +
                        "found both %2$d and %3$d", name, prevCount, count);
                context.report(ARG_COUNT, location, message, null);
                break;
            }

            for (int i = 1; i <= count; i++) {
                if (!indices.contains(i)) {
                    Object clientData = handle.getClientData();
                    if (clientData instanceof Node) {
                        if (context.getDriver().isSuppressed(null, ARG_COUNT,
                                (Node) clientData)) {
                            return;
                        }
                    }

                    Set<Integer> all = new HashSet<Integer>();
                    for (int j = 1; j < count; j++) {
                        all.add(j);
                    }
                    all.removeAll(indices);
                    List<Integer> sorted = new ArrayList<Integer>(all);
                    Collections.sort(sorted);
                    Location location = handle.resolve();
                    String message = String.format(
                            "Formatting string '%1$s' is not referencing numbered arguments %2$s",
                            name, sorted);
                    context.report(ARG_COUNT, location, message, null);
                    break;
View Full Code Here


        if (mIgnoreStrings != null && mIgnoreStrings.contains(name)) {
            return;
        }

        if (mNotFormatStrings.containsKey(name)) {
            Handle handle = mNotFormatStrings.get(name);
            Object clientData = handle.getClientData();
            if (clientData instanceof Node) {
                if (context.getDriver().isSuppressed(null, INVALID, (Node) clientData)) {
                    return;
                }
            }
            Location location = handle.resolve();
            String message = String.format(
                    "Format string '%1$s' is not a valid format string so it should not be " +
                    "passed to String.format",
                    name);
            context.report(INVALID, call, location, message, null);
            return;
        }

        Iterator<Expression> argIterator = args.iterator();
        Expression first = argIterator.next();
        Expression second = argIterator.hasNext() ? argIterator.next() : null;

        boolean specifiesLocale;
        TypeReference parameterType;
        lombok.ast.Node resolved = context.parser.resolve(context, first);
        if (resolved != null) {
            parameterType = context.parser.getType(context, resolved);
        } else {
            parameterType = context.parser.getType(context, first);
        }
        if (parameterType != null) {
            specifiesLocale = parameterType.getTypeName().equals("java.util.Locale"); //$NON-NLS-1$
        } else if (!call.astName().astValue().equals(FORMAT_METHOD)) {
            specifiesLocale = false;
        } else {
            // No type information with this AST; use string patterns instead to make
            // an educated guess
            String firstName = first.toString();
            specifiesLocale = firstName.startsWith("Locale.")                     //$NON-NLS-1$
                    || firstName.contains("locale")                               //$NON-NLS-1$
                    || firstName.equals("null")                                   //$NON-NLS-1$
                    || (second != null && second.toString().contains("getString") //$NON-NLS-1$
                        && !firstName.contains("getString")                       //$NON-NLS-1$
                        && !firstName.contains(R_PREFIX)
                        && !(first instanceof StringLiteral));
        }

        List<Pair<Handle, String>> list = mFormatStrings.get(name);
        if (list != null) {
            for (Pair<Handle, String> pair : list) {
                String s = pair.getSecond();
                int count = getFormatArgumentCount(s, null);
                Handle handle = pair.getFirst();
                if (count != args.size() - 1 - (specifiesLocale ? 1 : 0)) {
                    Location location = context.parser.getLocation(context, call);
                    Location secondary = handle.resolve();
                    secondary.setMessage(String.format("This definition requires %1$d arguments",
                            count));
                    location.setSecondary(secondary);
                    String message = String.format(
                            "Wrong argument count, format string %1$s requires %2$d but format " +
                            "call supplies %3$d",
                            name, count, args.size() - 1 - (specifiesLocale ? 1 : 0));
                    context.report(ARG_TYPES, method, location, message, null);
                } else {
                    for (int i = 1; i <= count; i++) {
                        int argumentIndex = i + (specifiesLocale ? 1 : 0);
                        Class<?> type = tracker.getArgumentType(argumentIndex);
                        if (type != null) {
                            boolean valid = true;
                            String formatType = getFormatArgumentType(s, i);
                            char last = formatType.charAt(formatType.length() - 1);
                            if (formatType.length() >= 2 &&
                                    Character.toLowerCase(
                                            formatType.charAt(formatType.length() - 2)) == 't') {
                                // Date time conversion.
                                // TODO
                                continue;
                            }
                            switch (last) {
                                // Booleans. It's okay to pass objects to these;
                                // it will print "true" if non-null, but it's
                                // unusual and probably not intended.
                                case 'b':
                                case 'B':
                                    valid = type == Boolean.TYPE;
                                    break;

                                // Numeric: integer and floats in various formats
                                case 'x':
                                case 'X':
                                case 'd':
                                case 'o':
                                case 'e':
                                case 'E':
                                case 'f':
                                case 'g':
                                case 'G':
                                case 'a':
                                case 'A':
                                    valid = type == Integer.TYPE
                                            || type == Float.TYPE;
                                    break;
                                case 'c':
                                case 'C':
                                    // Unicode character
                                    valid = type == Character.TYPE;
                                    break;
                                case 'h':
                                case 'H': // Hex print of hash code of objects
                                case 's':
                                case 'S':
                                    // String. Can pass anything, but warn about
                                    // numbers since you may have meant more
                                    // specific formatting. Use special issue
                                    // explanation for this?
                                    valid = type != Boolean.TYPE &&
                                        !type.isAssignableFrom(Number.class);
                                    break;
                            }

                            if (!valid) {
                                IJavaParser parser = context.parser;
                                Expression argument = tracker.getArgument(argumentIndex);
                                Location location = parser.getLocation(context, argument);
                                Location secondary = handle.resolve();
                                secondary.setMessage("Conflicting argument declaration here");
                                location.setSecondary(secondary);

                                String message = String.format(
                                        "Wrong argument type for formatting argument '#%1$d' " +
View Full Code Here

        if (mIncludes == null) {
            return;
        }

        for (Pair<String, Location.Handle> pending : mPending) {
            Handle handle = pending.getSecond();
            Location location = handle.resolve();
            File file = location.getFile();
            String layout = file.getName();
            if (layout.endsWith(DOT_XML)) {
                layout = layout.substring(0, layout.length() - DOT_XML.length());
            }

            List<Pair<File, String>> includes = mIncludes.get(layout);
            if (includes == null) {
                // Nobody included this file
                continue;
            }

            String name = pending.getFirst();
            String parent = PARAM_TO_VIEW.get(name);
            if (parent == null) {
                continue;
            }

            boolean isValid = false;
            for (Pair<File, String> include : includes) {
                String parentTag = include.getSecond();
                if (isValidParamForParent(context, name, parent, parentTag)) {
                    isValid = true;
                    break;
                } else if (!isValid && name.equals(ATTR_LAYOUT_COLUMN)
                        && isValidParamForParent(context, name, TABLE_ROW, parentTag)) {
                    isValid = true;
                    break;
                }
            }

            if (!isValid) {
                Object clientData = handle.getClientData();
                if (clientData instanceof Node) {
                    if (context.getDriver().isSuppressed(null, ISSUE, (Node) clientData)) {
                        return;
                    }
                }
View Full Code Here

                // Also make sure this String isn't an unformatted String
                String formatted = element.getAttribute("formatted"); //$NON-NLS-1$
                if (!formatted.isEmpty() && !Boolean.parseBoolean(formatted)) {
                    if (!mNotFormatStrings.containsKey(name)) {
                        Handle handle = context.parser.createLocationHandle(context, element);
                        handle.setClientData(element);
                        mNotFormatStrings.put(name, handle);
                    }
                    return;
                }

                // See if it's not a format string, e.g. "Battery charge is 100%!".
                // If so we want to record this name in a special list such that we can
                // make sure you don't attempt to reference this string from a String.format
                // call.
                Matcher matcher = FORMAT.matcher(text);
                if (!matcher.find(j)) {
                    if (!mNotFormatStrings.containsKey(name)) {
                        Handle handle = context.parser.createLocationHandle(context, element);
                        handle.setClientData(element);
                        mNotFormatStrings.put(name, handle);
                    }
                    return;
                }

                String conversion = matcher.group(6);
                int conversionClass = getConversionClass(conversion.charAt(0));
                if (conversionClass == CONVERSION_CLASS_UNKNOWN || matcher.group(5) != null) {
                    if (mIgnoreStrings == null) {
                        mIgnoreStrings = new HashSet<String>();
                    }
                    mIgnoreStrings.add(name);

                    // Don't process any other strings here; some of them could
                    // accidentally look like a string, e.g. "%H" is a hash code conversion
                    // in String.format (and hour in Time formatting).
                    return;
                }

                found = true;
                j++; // Ensure that when we process a "%%" we don't separately check the second %
            }
        }

        if (found && name != null) {
            if (!context.getProject().getReportIssues()) {
                // If this is a library project not being analyzed, ignore it
                return;
            }

            // Record it for analysis when seen in Java code
            if (mFormatStrings == null) {
                mFormatStrings = new HashMap<String, List<Pair<Handle,String>>>();
            }

            List<Pair<Handle, String>> list = mFormatStrings.get(name);
            if (list == null) {
                list = new ArrayList<Pair<Handle, String>>();
                mFormatStrings.put(name, list);
            }
            Handle handle = context.parser.createLocationHandle(context, element);
            handle.setClientData(element);
            list.add(Pair.of(handle, text));
        }
    }
View Full Code Here

    private static void checkTypes(Context context, boolean checkValid,
            boolean checkTypes, String name, List<Pair<Handle, String>> list) {
        Map<Integer, String> types = new HashMap<Integer, String>();
        Map<Integer, Handle> typeDefinition = new HashMap<Integer, Handle>();
        for (Pair<Handle, String> pair : list) {
            Handle handle = pair.getFirst();
            String formatString = pair.getSecond();

            //boolean warned = false;
            Matcher matcher = FORMAT.matcher(formatString);
            int index = 0;
            int prevIndex = 0;
            int nextNumber = 1;
            while (true) {
                if (matcher.find(index)) {
                    int matchStart = matcher.start();
                    // Make sure this is not an escaped '%'
                    for (; prevIndex < matchStart; prevIndex++) {
                        char c = formatString.charAt(prevIndex);
                        if (c == '\\') {
                            prevIndex++;
                        }
                    }
                    if (prevIndex > matchStart) {
                        // We're in an escape, ignore this result
                        index = prevIndex;
                        continue;
                    }

                    index = matcher.end(); // Ensure loop proceeds
                    String str = formatString.substring(matchStart, matcher.end());
                    if (str.equals("%%")) { //$NON-NLS-1$
                        // Just an escaped %
                        continue;
                    }

                    if (checkValid) {
                        // Make sure it's a valid format string
                        if (str.length() > 2 && str.charAt(str.length() - 2) == ' ') {
                            char last = str.charAt(str.length() - 1);
                            // If you forget to include the conversion character, e.g.
                            //   "Weight=%1$ g" instead of "Weight=%1$d g", then
                            // you're going to end up with a format string interpreted as
                            // "%1$ g". This means that the space character is interpreted
                            // as a flag character, but it can only be a flag character
                            // when used in conjunction with the numeric conversion
                            // formats (d, o, x, X). If that's not the case, make a
                            // dedicated error message
                            if (last != 'd' && last != 'o' && last != 'x' && last != 'X') {
                                Object clientData = handle.getClientData();
                                if (clientData instanceof Node) {
                                    if (context.getDriver().isSuppressed(null, INVALID,
                                            (Node) clientData)) {
                                        return;
                                    }
                                }

                                Location location = handle.resolve();
                                String message = String.format(
                                        "Incorrect formatting string %1$s; missing conversion " +
                                        "character in '%2$s' ?", name, str);
                                context.report(INVALID, location, message, null);
                                //warned = true;
                                continue;
                            }
                        }
                    }

                    if (!checkTypes) {
                        continue;
                    }

                    // Shouldn't throw a number format exception since we've already
                    // matched the pattern in the regexp
                    int number;
                    String numberString = matcher.group(1);
                    if (numberString != null) {
                        // Strip off trailing $
                        numberString = numberString.substring(0, numberString.length() - 1);
                        number = Integer.parseInt(numberString);
                        nextNumber = number + 1;
                    } else {
                        number = nextNumber++;
                    }
                    String format = matcher.group(6);
                    String currentFormat = types.get(number);
                    if (currentFormat == null) {
                        types.put(number, format);
                        typeDefinition.put(number, handle);
                    } else if (!currentFormat.equals(format)
                            && isIncompatible(currentFormat.charAt(0), format.charAt(0))) {

                        Object clientData = handle.getClientData();
                        if (clientData instanceof Node) {
                            if (context.getDriver().isSuppressed(null, ARG_TYPES,
                                    (Node) clientData)) {
                                return;
                            }
                        }

                        Location location = handle.resolve();
                        // Attempt to limit the location range to just the formatting
                        // string in question
                        location = refineLocation(context, location, formatString,
                                matcher.start(), matcher.end());
                        Location otherLocation = typeDefinition.get(number).resolve();
View Full Code Here

        if (!context.getProject().getReportIssues()) {
            // If this is a library project not being analyzed, ignore it
            return;
        }

        Handle handle = null;
        if (!context.getDriver().isSuppressed(context, MISSING, element)) {
            if (mReferencedClasses == null) {
                mReferencedClasses = Maps.newHashMapWithExpectedSize(16);
                mCustomViews = Sets.newHashSetWithExpectedSize(8);
            }
View Full Code Here

        if (!context.getProject().getReportIssues()) {
            // If this is a library project not being analyzed, ignore it
            return;
        }

        Handle handle = null;
        if (!context.getDriver().isSuppressed(context, MISSING, element)) {
            if (mReferencedClasses == null) {
                mReferencedClasses = Maps.newHashMapWithExpectedSize(16);
                mCustomViews = Sets.newHashSetWithExpectedSize(8);
            }
View Full Code Here

TOP

Related Classes of com.android.tools.lint.detector.api.Location.Handle

Copyright © 2018 www.massapicom. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.