blob: 7127b82834d3c0b3122b69a75847b37db7737a1b [file] [log] [blame]
/*
* Copyright (c) 2022 Uber Technologies, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.uber.nullaway.fixserialization.out;
import com.google.common.collect.ImmutableMap;
import com.google.errorprone.util.ASTHelpers;
import com.sun.source.util.TreePath;
import com.sun.tools.javac.code.Symbol;
import com.uber.nullaway.ErrorMessage;
import com.uber.nullaway.fixserialization.location.SymbolLocation;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.Nullable;
/** Stores information regarding an error which will be reported by NullAway. */
public class ErrorInfo {
private final ErrorMessage errorMessage;
private final ClassAndMemberInfo classAndMemberInfo;
/**
* if non-null, this error involved a pseudo-assignment of a @Nullable expression into a @NonNull
* target, and this field is the Symbol for that target.
*/
@Nullable private final Symbol nonnullTarget;
/**
* In cases where {@link ErrorInfo#nonnullTarget} is {@code null}, we serialize this value at its
* placeholder in the output tsv file.
*/
private static final String EMPTY_NONNULL_TARGET_LOCATION_STRING =
"null\tnull\tnull\tnull\tnull\tnull";
/** Special characters that need to be escaped in TSV files. */
private static final ImmutableMap<Character, Character> escapes =
ImmutableMap.of(
'\n', 'n',
'\t', 't',
'\f', 'f',
'\b', 'b',
'\r', 'r');
public ErrorInfo(TreePath path, ErrorMessage errorMessage, @Nullable Symbol nonnullTarget) {
this.classAndMemberInfo = new ClassAndMemberInfo(path);
this.errorMessage = errorMessage;
this.nonnullTarget = nonnullTarget;
}
/**
* Escapes special characters in string to conform with TSV file formats. The most common
* convention for lossless conversion is to escape special characters with a backslash according
* to <a
* href="https://en.wikipedia.org/wiki/Tab-separated_values#Conventions_for_lossless_conversion_to_TSV">
* Conventions for lossless conversion to TSV</a>
*
* @param str String to process.
* @return returns modified str which its special characters are escaped.
*/
private static String escapeSpecialCharacters(String str) {
// regex needs "\\" to match character '\', each must also be escaped in string to create "\\",
// therefore we need four "\".
// escape existing backslashes
str = str.replaceAll(Pattern.quote("\\"), Matcher.quoteReplacement("\\\\"));
// escape special characters
for (Character key : escapes.keySet()) {
str = str.replaceAll(String.valueOf(key), Matcher.quoteReplacement("\\" + escapes.get(key)));
}
return str;
}
/**
* returns string representation of content of an object.
*
* @return string representation of contents of an object in a line seperated by tabs.
*/
public String tabSeparatedToString() {
return String.join(
"\t",
errorMessage.getMessageType().toString(),
escapeSpecialCharacters(errorMessage.getMessage()),
(classAndMemberInfo.getClazz() != null
? ASTHelpers.getSymbol(classAndMemberInfo.getClazz()).flatName()
: "null"),
(classAndMemberInfo.getMember() != null
? classAndMemberInfo.getMember().toString()
: "null"),
(nonnullTarget != null
? SymbolLocation.createLocationFromSymbol(nonnullTarget).tabSeparatedToString()
: EMPTY_NONNULL_TARGET_LOCATION_STRING));
}
/** Finds the class and member of program point where the error is reported. */
public void initEnclosing() {
classAndMemberInfo.findValues();
}
/**
* Creates header of an output file containing all {@link ErrorInfo} written in string which
* values are separated tabs.
*
* @return string representation of the header separated by tabs.
*/
public static String header() {
return String.join(
"\t",
"message_type",
"message",
"enc_class",
"enc_member",
"target_kind",
"target_class",
"target_method",
"param",
"index",
"uri");
}
}