Search in sources :

Example 36 with Location

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

the class StringFormatDetector method checkNotFormattedHandle.

/**
     * Checks a String.format call that is using a string that doesn't contain format placeholders.
     * @param context the context to report errors to
     * @param call the AST node for the {@link String#format}
     * @param name the string name
     * @param handle the string location
     */
private static void checkNotFormattedHandle(JavaContext context, UCallExpression call, String name, Handle handle) {
    Object clientData = handle.getClientData();
    if (clientData instanceof Node) {
        if (context.getDriver().isSuppressed(null, INVALID, (Node) clientData)) {
            return;
        }
    }
    Location location = context.getUastLocation(call);
    Location secondary = handle.resolve();
    secondary.setMessage("This definition does not require arguments");
    location.setSecondary(secondary);
    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);
}
Also used : Node(org.w3c.dom.Node) Location(com.android.tools.klint.detector.api.Location)

Example 37 with Location

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

the class StringFormatDetector method checkTypes.

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;
                }
                // Ensure loop proceeds
                index = matcher.end();
                String str = formatString.substring(matchStart, matcher.end());
                if (str.equals("%%") || str.equals("%n")) {
                    // 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);
                        // 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);
                            //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();
                    otherLocation.setMessage("Conflicting argument type here");
                    location.setSecondary(otherLocation);
                    File f = otherLocation.getFile();
                    String message = String.format("Inconsistent formatting types for argument #%1$d in " + "format string `%2$s` ('%3$s'): Found both '`%4$s`' and '`%5$s`' " + "(in %6$s)", number, name, str, currentFormat, format, f.getParentFile().getName() + File.separator + f.getName());
                    //warned = true;
                    context.report(ARG_TYPES, location, message);
                    break;
                }
            } else {
                break;
            }
        }
    // Check that the format string is valid by actually attempting to instantiate
    // it. We only do this if we haven't already complained about this string
    // for other reasons.
    /* Check disabled for now: it had many false reports due to conversion
             * errors (which is expected since we just pass in strings), but once those
             * are eliminated there aren't really any other valid error messages returned
             * (for example, calling the formatter with bogus formatting flags always just
             * returns a "conversion" error. It looks like we'd need to actually pass compatible
             * arguments to trigger other types of formatting errors such as precision errors.
            if (!warned && checkValid) {
                try {
                    formatter.format(formatString, "", "", "", "", "", "", "",
                            "", "", "", "", "", "", "");

                } catch (IllegalFormatException t) { // TODO: UnknownFormatConversionException
                    if (!t.getLocalizedMessage().contains(" != ")
                            && !t.getLocalizedMessage().contains("Conversion")) {
                        Location location = handle.resolve();
                        context.report(INVALID, location,
                                String.format("Wrong format for %1$s: %2$s",
                                        name, t.getLocalizedMessage()), null);
                    }
                }
            }
            */
    }
}
Also used : HashMap(java.util.HashMap) Matcher(java.util.regex.Matcher) Node(org.w3c.dom.Node) Handle(com.android.tools.klint.detector.api.Location.Handle) File(java.io.File) Location(com.android.tools.klint.detector.api.Location)

Example 38 with Location

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

the class LintDriver method checkClasses.

/** Check the classes in this project (and if applicable, in any library projects */
private void checkClasses(Project project, Project main) {
    List<File> files = project.getSubset();
    if (files != null) {
        checkIndividualClassFiles(project, main, files);
        return;
    }
    // We need to read in all the classes up front such that we can initialize
    // the parent chains (such that for example for a virtual dispatch, we can
    // also check the super classes).
    List<File> libraries = project.getJavaLibraries(false);
    List<ClassEntry> libraryEntries = ClassEntry.fromClassPath(mClient, libraries, true);
    List<File> classFolders = project.getJavaClassFolders();
    List<ClassEntry> classEntries;
    if (classFolders.isEmpty()) {
        String message = String.format("No `.class` files were found in project \"%1$s\", " + "so none of the classfile based checks could be run. " + "Does the project need to be built first?", project.getName());
        Location location = Location.create(project.getDir());
        mClient.report(new Context(this, project, main, project.getDir()), IssueRegistry.LINT_ERROR, project.getConfiguration(this).getSeverity(IssueRegistry.LINT_ERROR), location, message, TextFormat.RAW);
        classEntries = Collections.emptyList();
    } else {
        classEntries = ClassEntry.fromClassPath(mClient, classFolders, true);
    }
    // Actually run the detectors. Libraries should be called before the
    // main classes.
    runClassDetectors(Scope.JAVA_LIBRARIES, libraryEntries, project, main);
    if (mCanceled) {
        return;
    }
    runClassDetectors(Scope.CLASS_FILE, classEntries, project, main);
    runClassDetectors(Scope.ALL_CLASS_FILES, classEntries, project, main);
}
Also used : ClassContext(com.android.tools.klint.detector.api.ClassContext) XmlContext(com.android.tools.klint.detector.api.XmlContext) JavaContext(com.android.tools.klint.detector.api.JavaContext) ResourceContext(com.android.tools.klint.detector.api.ResourceContext) Context(com.android.tools.klint.detector.api.Context) File(java.io.File) PsiFile(com.intellij.psi.PsiFile) Location(com.android.tools.klint.detector.api.Location)

Aggregations

Location (com.android.tools.klint.detector.api.Location)38 UExpression (org.jetbrains.uast.UExpression)8 JavaEvaluator (com.android.tools.klint.client.api.JavaEvaluator)7 File (java.io.File)7 PsiElement (com.intellij.psi.PsiElement)4 PsiMethod (com.intellij.psi.PsiMethod)4 ArrayList (java.util.ArrayList)4 Attr (org.w3c.dom.Attr)4 Node (org.w3c.dom.Node)4 Handle (com.android.tools.klint.detector.api.Location.Handle)3 XmlContext (com.android.tools.klint.detector.api.XmlContext)3 PsiClassType (com.intellij.psi.PsiClassType)3 PsiType (com.intellij.psi.PsiType)3 List (java.util.List)3 UAnonymousClass (org.jetbrains.uast.UAnonymousClass)3 NodeList (org.w3c.dom.NodeList)3 NonNull (com.android.annotations.NonNull)2 ResourceType (com.android.resources.ResourceType)2 ClassContext (com.android.tools.klint.detector.api.ClassContext)2 Context (com.android.tools.klint.detector.api.Context)2