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);
}
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);
}
}
}
*/
}
}
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);
}
Aggregations