diff options
Diffstat (limited to 'platform/util/src/com/intellij')
19 files changed, 724 insertions, 81 deletions
diff --git a/platform/util/src/com/intellij/execution/configurations/CommandLineTokenizer.java b/platform/util/src/com/intellij/execution/configurations/CommandLineTokenizer.java index a62af9aa62dc..3f351b9a573e 100644 --- a/platform/util/src/com/intellij/execution/configurations/CommandLineTokenizer.java +++ b/platform/util/src/com/intellij/execution/configurations/CommandLineTokenizer.java @@ -20,9 +20,9 @@ import java.util.List; import java.util.StringTokenizer; /** - * Splits input String to tokens being aware of quoted tokens ("foo bar") and escaped spaces (foo\ bar), + * Splits input String to tokens being aware of quoted tokens ("foo bar") and escaped spaces & quotes (\"foo\ bar\"), * usually used for splitting command line to separate arguments that may contain space symbols. - * Escaped symbols are not handled so there's no way to get token that itself contains quotation mark. + * Space and quote are the only symbols that can be escaped */ public class CommandLineTokenizer extends StringTokenizer { @@ -103,8 +103,10 @@ public class CommandLineTokenizer extends StringTokenizer { do { while ((i = nextToken.indexOf('"')) >= 0) { - quotationMarks++; - buffer.append(nextToken.substring(0, i)); + boolean isEscapedQuote = i > 0 && nextToken.charAt(i - 1) == '\\'; + if (!isEscapedQuote) quotationMarks++; + buffer.append(nextToken.substring(0, isEscapedQuote ? i - 1 : i)); + if (isEscapedQuote) buffer.append('"'); nextToken = nextToken.substring(i + 1); } diff --git a/platform/util/src/com/intellij/icons/AllIcons.java b/platform/util/src/com/intellij/icons/AllIcons.java index a80ffccdd58e..f31f9b94b058 100644 --- a/platform/util/src/com/intellij/icons/AllIcons.java +++ b/platform/util/src/com/intellij/icons/AllIcons.java @@ -204,6 +204,7 @@ public class AllIcons { public static final Icon AutoVariablesMode = IconLoader.getIcon("/debugger/autoVariablesMode.png"); // 16x16 public static final Icon BreakpointAlert = IconLoader.getIcon("/debugger/breakpointAlert.png"); // 16x16 public static final Icon Class_filter = IconLoader.getIcon("/debugger/class_filter.png"); // 16x16 + public static final Icon CommandLine = IconLoader.getIcon("/debugger/commandLine.png"); // 16x16 public static final Icon Console = IconLoader.getIcon("/debugger/console.png"); // 16x16 public static final Icon Db_array = IconLoader.getIcon("/debugger/db_array.png"); // 16x16 public static final Icon Db_db_object = IconLoader.getIcon("/debugger/db_db_object.png"); // 16x16 diff --git a/platform/util/src/com/intellij/openapi/application/PathManager.java b/platform/util/src/com/intellij/openapi/application/PathManager.java index 9956959f0e22..0188203cde33 100644 --- a/platform/util/src/com/intellij/openapi/application/PathManager.java +++ b/platform/util/src/com/intellij/openapi/application/PathManager.java @@ -45,7 +45,6 @@ public class PathManager { @NonNls public static final String PROPERTY_HOME_PATH = "idea.home.path"; @NonNls public static final String PROPERTY_LOG_PATH = "idea.log.path"; @NonNls public static final String PROPERTY_PATHS_SELECTOR = "idea.paths.selector"; - @NonNls public static final String PROPERTY_ORIGINAL_WORKING_DIR = "original.working.dir"; @NonNls public static final String DEFAULT_OPTIONS_FILE_NAME = "other"; @NonNls private static final String LIB_FOLDER = "lib"; @@ -253,11 +252,6 @@ public class PathManager { // misc stuff - @Nullable - public static String getOriginalWorkingDir() { - return System.getProperty(PROPERTY_ORIGINAL_WORKING_DIR); - } - /** * Attempts to detect classpath entry which contains given resource. */ @@ -418,7 +412,7 @@ public class PathManager { private static String getAbsolutePath(String path) { path = FileUtil.expandUserHome(path); - return FileUtil.toCanonicalPath(new File(FileUtil.toCanonicalPath(path)).getAbsolutePath()); + return FileUtil.toCanonicalPath(new File(path).getAbsolutePath()); } private static String trimPathQuotes(String path){ diff --git a/platform/util/src/com/intellij/openapi/util/JDOMExternalizer.java b/platform/util/src/com/intellij/openapi/util/JDOMExternalizer.java index 909c44db199b..cd5e8630a087 100644 --- a/platform/util/src/com/intellij/openapi/util/JDOMExternalizer.java +++ b/platform/util/src/com/intellij/openapi/util/JDOMExternalizer.java @@ -22,7 +22,10 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.*; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; public class JDOMExternalizer { private JDOMExternalizer() { @@ -66,7 +69,7 @@ public class JDOMExternalizer { return null; } - public static void writeMap(Element root, Map<String, String>map, @NonNls @Nullable String rootName, @NonNls String entryName) { + public static void writeMap(Element root, Map<String, String> map, @NonNls @Nullable String rootName, @NonNls String entryName) { Element mapRoot; if (StringUtil.isNotEmpty(rootName)) { mapRoot = new Element(rootName); @@ -106,6 +109,26 @@ public class JDOMExternalizer { } } + /** + * Saves a pack of strings to some attribte. I.e: [tag attr="value"] + * @param parent parent element (where to add newly created tags) + * @param nodeName node name (tag, in our example) + * @param attrName attribute name (attr, in our example) + * @param values a pack of values to add + * @see #loadStringsList(org.jdom.Element, String, String) + */ + public static void saveStringsList(@NotNull final Element parent, + @NotNull final String nodeName, + @NotNull final String attrName, + @NotNull final String... values) { + for (final String value : values) { + final Element node = new Element(nodeName); + node.setAttribute(attrName, value); + parent.addContent(node); + } + } + + @NotNull public static List<String> loadStringsList(Element element, String rootName, String attrName) { final List<String> paths = new LinkedList<String>(); if (element != null) { diff --git a/platform/util/src/com/intellij/openapi/util/JDOMUtil.java b/platform/util/src/com/intellij/openapi/util/JDOMUtil.java index c82ee6df346b..dfee1dbed2df 100644 --- a/platform/util/src/com/intellij/openapi/util/JDOMUtil.java +++ b/platform/util/src/com/intellij/openapi/util/JDOMUtil.java @@ -398,9 +398,13 @@ public class JDOMUtil { } public static void writeDocument(@NotNull Document document, @NotNull File file, String lineSeparator) throws IOException { + writeParent(document, file, lineSeparator); + } + + public static void writeParent(@NotNull Parent element, @NotNull File file, String lineSeparator) throws IOException { OutputStream stream = new BufferedOutputStream(new FileOutputStream(file)); try { - writeDocument(document, stream, lineSeparator); + writeParent(element, stream, lineSeparator); } finally { stream.close(); @@ -408,9 +412,23 @@ public class JDOMUtil { } public static void writeDocument(@NotNull Document document, @NotNull OutputStream stream, String lineSeparator) throws IOException { - writeDocument(document, new OutputStreamWriter(stream, CharsetToolkit.UTF8_CHARSET), lineSeparator); + writeParent(document, stream, lineSeparator); } + public static void writeParent(@NotNull Parent element, @NotNull OutputStream stream, @NotNull String lineSeparator) throws IOException { + OutputStreamWriter writer = new OutputStreamWriter(stream, CharsetToolkit.UTF8_CHARSET); + try { + if (element instanceof Document) { + writeDocument((Document)element, writer, lineSeparator); + } + else { + writeElement((Element) element, writer, lineSeparator); + } + } + finally { + writer.close(); + } + } @NotNull public static byte[] printDocument(@NotNull Document document, String lineSeparator) throws IOException { diff --git a/platform/util/src/com/intellij/openapi/util/io/FileUtil.java b/platform/util/src/com/intellij/openapi/util/io/FileUtil.java index 7d3d6f557249..bc41f70e933a 100644 --- a/platform/util/src/com/intellij/openapi/util/io/FileUtil.java +++ b/platform/util/src/com/intellij/openapi/util/io/FileUtil.java @@ -1249,18 +1249,15 @@ public class FileUtil extends FileUtilRt { } public static boolean isWindowsAbsolutePath(@NotNull String pathString) { - if (pathString.length() >= 2 && Character.isLetter(pathString.charAt(0)) && pathString.charAt(1) == ':') { - return true; - } - return false; + return pathString.length() >= 2 && Character.isLetter(pathString.charAt(0)) && pathString.charAt(1) == ':'; } - @Contract("null -> null") + @Contract("null -> null; !null -> !null") public static String getLocationRelativeToUserHome(@Nullable String path) { return getLocationRelativeToUserHome(path, true); } - @Contract("null,_ -> null") + @Contract("null,_ -> null; !null,_ -> !null") public static String getLocationRelativeToUserHome(@Nullable String path, boolean unixOnly) { if (path == null) return null; diff --git a/platform/util/src/com/intellij/openapi/util/text/StringUtil.java b/platform/util/src/com/intellij/openapi/util/text/StringUtil.java index af2b3dd4293e..c2b7de8ba7ed 100644 --- a/platform/util/src/com/intellij/openapi/util/text/StringUtil.java +++ b/platform/util/src/com/intellij/openapi/util/text/StringUtil.java @@ -64,6 +64,7 @@ public class StringUtil extends StringUtilRt { }; @NotNull + @Contract(pure = true) public static List<String> getWordsInStringLongestFirst(@NotNull String find) { List<String> words = getWordsIn(find); // hope long words are rare @@ -77,11 +78,13 @@ public class StringUtil extends StringUtilRt { } @NotNull + @Contract(pure = true) public static String escapePattern(@NotNull final String text) { return replace(replace(text, "'", "''"), "{", "'{'"); } @NotNull + @Contract(pure = true) public static <T> Function<T, String> createToStringFunction(@NotNull Class<T> cls) { return new Function<T, String>() { @Override @@ -101,11 +104,13 @@ public class StringUtil extends StringUtilRt { }; @NotNull + @Contract(pure = true) public static String replace(@NonNls @NotNull String text, @NonNls @NotNull String oldS, @NonNls @NotNull String newS) { return replace(text, oldS, newS, false); } @NotNull + @Contract(pure = true) public static String replaceIgnoreCase(@NonNls @NotNull String text, @NonNls @NotNull String oldS, @NonNls @NotNull String newS) { return replace(text, oldS, newS, true); } @@ -120,6 +125,7 @@ public class StringUtil extends StringUtilRt { } @NotNull + @Contract(pure = true) public static String replaceChar(@NotNull String buffer, char oldChar, char newChar) { StringBuilder newBuffer = null; for (int i = 0; i < buffer.length(); i++) { @@ -139,6 +145,7 @@ public class StringUtil extends StringUtilRt { return newBuffer == null ? buffer : newBuffer.toString(); } + @Contract(pure = true) public static String replace(@NonNls @NotNull final String text, @NonNls @NotNull final String oldS, @NonNls @NotNull final String newS, final boolean ignoreCase) { if (text.length() < oldS.length()) return text; @@ -146,17 +153,26 @@ public class StringUtil extends StringUtilRt { int i = 0; while (i < text.length()) { - final int i1 = ignoreCase? indexOfIgnoreCase(text, oldS, i) : text.indexOf(oldS, i); - if (i1 < 0) { - if (i == 0) return text; + final int index = ignoreCase? indexOfIgnoreCase(text, oldS, i) : text.indexOf(oldS, i); + if (index < 0) { + if (i == 0) { + return text; + } + newText.append(text, i, text.length()); break; } else { - if (newText == null) newText = new StringBuilder(text.length() - i); - newText.append(text, i, i1); + if (newText == null) { + if (text.length() == oldS.length()) { + return newS; + } + newText = new StringBuilder(text.length() - i); + } + + newText.append(text, i, index); newText.append(newS); - i = i1 + oldS.length(); + i = index + oldS.length(); } } return newText != null ? newText.toString() : ""; @@ -165,6 +181,7 @@ public class StringUtil extends StringUtilRt { /** * Implementation copied from {@link String#indexOf(String, int)} except character comparisons made case insensitive */ + @Contract(pure = true) public static int indexOfIgnoreCase(@NotNull String where, @NotNull String what, int fromIndex) { int targetCount = what.length(); int sourceCount = where.length(); @@ -206,6 +223,7 @@ public class StringUtil extends StringUtilRt { return -1; } + @Contract(pure = true) public static int indexOfIgnoreCase(@NotNull String where, char what, int fromIndex) { int sourceCount = where.length(); @@ -226,18 +244,22 @@ public class StringUtil extends StringUtilRt { return -1; } + @Contract(pure = true) public static boolean containsIgnoreCase(@NotNull String where, @NotNull String what) { return indexOfIgnoreCase(where, what, 0) >= 0; } + @Contract(pure = true) public static boolean endsWithIgnoreCase(@NonNls @NotNull String str, @NonNls @NotNull String suffix) { return StringUtilRt.endsWithIgnoreCase(str, suffix); } + @Contract(pure = true) public static boolean startsWithIgnoreCase(@NonNls @NotNull String str, @NonNls @NotNull String prefix) { return StringUtilRt.startsWithIgnoreCase(str, prefix); } + @Contract(pure = true) public static String stripHtml(@NotNull String html, boolean convertBreaks) { if (convertBreaks) { html = html.replaceAll("<br/?>", "\n\n"); @@ -246,18 +268,20 @@ public class StringUtil extends StringUtilRt { return html.replaceAll("<(.|\n)*?>", ""); } - @Contract("null -> null; !null -> !null") + @Contract(value = "null -> null; !null -> !null", pure = true) public static String toLowerCase(@Nullable final String str) { //noinspection ConstantConditions return str == null ? null : str.toLowerCase(); } @NotNull + @Contract(pure = true) public static String getPackageName(@NotNull String fqName) { return getPackageName(fqName, '.'); } @NotNull + @Contract(pure = true) public static String getPackageName(@NotNull String fqName, char separator) { int lastPointIdx = fqName.lastIndexOf(separator); if (lastPointIdx >= 0) { @@ -266,6 +290,7 @@ public class StringUtil extends StringUtilRt { return ""; } + @Contract(pure = true) public static int getLineBreakCount(@NotNull CharSequence text) { int count = 0; for (int i = 0; i < text.length(); i++) { @@ -287,6 +312,7 @@ public class StringUtil extends StringUtilRt { return count; } + @Contract(pure = true) public static boolean containsLineBreak(@NotNull CharSequence text) { for (int i = 0; i < text.length(); i++) { char c = text.charAt(i); @@ -295,11 +321,13 @@ public class StringUtil extends StringUtilRt { return false; } + @Contract(pure = true) public static boolean isLineBreak(char c) { return c == '\n' || c == '\r'; } @NotNull + @Contract(pure = true) public static String escapeLineBreak(@NotNull String text) { StringBuilder buffer = new StringBuilder(text.length()); for (int i = 0; i < text.length(); i++) { @@ -318,11 +346,13 @@ public class StringUtil extends StringUtilRt { return buffer.toString(); } + @Contract(pure = true) public static boolean endsWithLineBreak(@NotNull CharSequence text) { int len = text.length(); return len > 0 && isLineBreak(text.charAt(len - 1)); } + @Contract(pure = true) public static int lineColToOffset(@NotNull CharSequence text, int line, int col) { int curLine = 0; int offset = 0; @@ -343,6 +373,7 @@ public class StringUtil extends StringUtilRt { return offset + col; } + @Contract(pure = true) public static int offsetToLineNumber(@NotNull CharSequence text, int offset) { int curLine = 0; int curOffset = 0; @@ -366,6 +397,7 @@ public class StringUtil extends StringUtilRt { /** * Classic dynamic programming algorithm for string differences. */ + @Contract(pure = true) public static int difference(@NotNull String s1, @NotNull String s2) { int[][] a = new int[s1.length()][s2.length()]; @@ -388,11 +420,13 @@ public class StringUtil extends StringUtilRt { } @NotNull + @Contract(pure = true) public static String wordsToBeginFromUpperCase(@NotNull String s) { return toTitleCase(s, ourPrepositions); } @NotNull + @Contract(pure = true) public static String toTitleCase(@NotNull String s) { return toTitleCase(s, ArrayUtil.EMPTY_STRING_ARRAY); } @@ -435,10 +469,12 @@ public class StringUtil extends StringUtilRt { "per", "nor", "the", "to", "up", "upon", "via", "with" }; + @Contract(pure = true) public static boolean isPreposition(@NotNull String s, int firstChar, int lastChar) { return isPreposition(s, firstChar, lastChar, ourPrepositions); } + @Contract(pure = true) public static boolean isPreposition(@NotNull String s, int firstChar, int lastChar, @NotNull String[] prepositions) { for (String preposition : prepositions) { boolean found = false; @@ -458,6 +494,7 @@ public class StringUtil extends StringUtilRt { } @NotNull + @Contract(pure = true) public static NotNullFunction<String, String> escaper(final boolean escapeSlash, @Nullable final String additionalChars) { return new NotNullFunction<String, String>() { @NotNull @@ -538,6 +575,7 @@ public class StringUtil extends StringUtilRt { return buffer; } + @Contract(pure = true) private static boolean isPrintableUnicode(char c) { int t = Character.getType(c); return t != Character.UNASSIGNED && t != Character.LINE_SEPARATOR && t != Character.PARAGRAPH_SEPARATOR && @@ -545,6 +583,7 @@ public class StringUtil extends StringUtilRt { } @NotNull + @Contract(pure = true) public static String escapeStringCharacters(@NotNull String s) { StringBuilder buffer = new StringBuilder(s.length()); escapeStringCharacters(s.length(), s, "\"", buffer); @@ -552,6 +591,7 @@ public class StringUtil extends StringUtilRt { } @NotNull + @Contract(pure = true) public static String escapeCharCharacters(@NotNull String s) { StringBuilder buffer = new StringBuilder(s.length()); escapeStringCharacters(s.length(), s, "\'", buffer); @@ -559,6 +599,7 @@ public class StringUtil extends StringUtilRt { } @NotNull + @Contract(pure = true) public static String unescapeStringCharacters(@NotNull String s) { StringBuilder buffer = new StringBuilder(s.length()); unescapeStringCharacters(s.length(), s, buffer); @@ -566,6 +607,7 @@ public class StringUtil extends StringUtilRt { } @NotNull + @Contract(pure = true) public static String unquoteString(@NotNull String s) { char c; if (s.length() <= 1 || (c = s.charAt(0)) != '"' && c != '\'' || s.charAt(s.length() - 1) != c) { @@ -575,6 +617,7 @@ public class StringUtil extends StringUtilRt { } @NotNull + @Contract(pure = true) public static String unquoteString(@NotNull String s, char quotationChar) { char c; if (s.length() <= 1 || (c = s.charAt(0)) != quotationChar || s.charAt(s.length() - 1) != c) { @@ -587,6 +630,7 @@ public class StringUtil extends StringUtilRt { * This is just an optimized version of Matcher.quoteReplacement */ @NotNull + @Contract(pure = true) public static String quoteReplacement(@NotNull String s) { boolean needReplacements = false; @@ -693,6 +737,7 @@ public class StringUtil extends StringUtilRt { @SuppressWarnings({"HardCodedStringLiteral"}) @NotNull + @Contract(pure = true) public static String pluralize(@NotNull String suggestion) { if (suggestion.endsWith("Child") || suggestion.endsWith("child")) { return suggestion + "ren"; @@ -718,12 +763,14 @@ public class StringUtil extends StringUtilRt { } @NotNull + @Contract(pure = true) public static String capitalizeWords(@NotNull String text, boolean allWords) { return capitalizeWords(text, " \t\n\r\f", allWords, false); } @NotNull + @Contract(pure = true) public static String capitalizeWords(@NotNull String text, @NotNull String tokenizerDelim, boolean allWords, @@ -744,15 +791,18 @@ public class StringUtil extends StringUtilRt { return out.toString(); } + @Contract(pure = true) public static String decapitalize(String s) { return Introspector.decapitalize(s); } + @Contract(pure = true) public static boolean isVowel(char c) { return VOWELS.indexOf(c) >= 0; } @NotNull + @Contract(pure = true) public static String capitalize(@NotNull String s) { if (s.isEmpty()) return s; if (s.length() == 1) return StringUtilRt.toUpperCase(s); @@ -762,12 +812,13 @@ public class StringUtil extends StringUtilRt { return toUpperCase(s.charAt(0)) + s.substring(1); } - @Contract("null -> false") + @Contract(value = "null -> false", pure = true) public static boolean isCapitalized(@Nullable String s) { return s != null && !s.isEmpty() && Character.isUpperCase(s.charAt(0)); } @NotNull + @Contract(pure = true) public static String capitalizeWithJavaBeanConvention(@NotNull String s) { if (s.length() > 1 && Character.isUpperCase(s.charAt(1))) { return s; @@ -775,6 +826,7 @@ public class StringUtil extends StringUtilRt { return capitalize(s); } + @Contract(pure = true) public static int stringHashCode(@NotNull CharSequence chars) { if (chars instanceof String) return chars.hashCode(); if (chars instanceof CharSequenceWithStringHash) return chars.hashCode(); @@ -783,6 +835,7 @@ public class StringUtil extends StringUtilRt { return stringHashCode(chars, 0, chars.length()); } + @Contract(pure = true) public static int stringHashCode(@NotNull CharSequence chars, int from, int to) { int h = 0; for (int off = from; off < to; off++) { @@ -791,6 +844,7 @@ public class StringUtil extends StringUtilRt { return h; } + @Contract(pure = true) public static int stringHashCode(char[] chars, int from, int to) { int h = 0; for (int off = from; off < to; off++) { @@ -799,6 +853,7 @@ public class StringUtil extends StringUtilRt { return h; } + @Contract(pure = true) public static int stringHashCodeInsensitive(@NotNull char[] chars, int from, int to) { int h = 0; for (int off = from; off < to; off++) { @@ -807,6 +862,7 @@ public class StringUtil extends StringUtilRt { return h; } + @Contract(pure = true) public static int stringHashCodeInsensitive(@NotNull CharSequence chars, int from, int to) { int h = 0; for (int off = from; off < to; off++) { @@ -815,6 +871,7 @@ public class StringUtil extends StringUtilRt { return h; } + @Contract(pure = true) public static int stringHashCodeInsensitive(@NotNull CharSequence chars) { return stringHashCodeInsensitive(chars, 0, chars.length()); } @@ -822,6 +879,7 @@ public class StringUtil extends StringUtilRt { /** * Equivalent to string.startsWith(prefixes[0] + prefixes[1] + ...) but avoids creating an object for concatenation. */ + @Contract(pure = true) public static boolean startsWithConcatenation(@NotNull String string, @NotNull String... prefixes) { int offset = 0; for (String prefix : prefixes) { @@ -838,6 +896,7 @@ public class StringUtil extends StringUtilRt { * @deprecated use {@link #startsWithConcatenation(String, String...)} (to remove in IDEA 14). */ @SuppressWarnings("UnusedDeclaration") + @Contract(pure = true) public static boolean startsWithConcatenationOf(@NotNull String string, @NotNull String firstPrefix, @NotNull String secondPrefix) { return startsWithConcatenation(string, firstPrefix, secondPrefix); } @@ -846,6 +905,7 @@ public class StringUtil extends StringUtilRt { * @deprecated use {@link #startsWithConcatenation(String, String...)} (to remove in IDEA 14). */ @SuppressWarnings("UnusedDeclaration") + @Contract(pure = true) public static boolean startsWithConcatenationOf(@NotNull String string, @NotNull String firstPrefix, @NotNull String secondPrefix, @@ -853,12 +913,13 @@ public class StringUtil extends StringUtilRt { return startsWithConcatenation(string, firstPrefix, secondPrefix, thirdPrefix); } - @Contract("null -> null; !null -> !null") + @Contract(value = "null -> null; !null -> !null", pure = true) public static String trim(@Nullable String s) { return s == null ? null : s.trim(); } @NotNull + @Contract(pure = true) public static String trimEnd(@NotNull String s, @NonNls @NotNull String suffix) { if (s.endsWith(suffix)) { return s.substring(0, s.length() - suffix.length()); @@ -867,6 +928,7 @@ public class StringUtil extends StringUtilRt { } @NotNull + @Contract(pure = true) public static String trimLog(@NotNull final String text, final int limit) { if (limit > 5 && text.length() > limit) { return text.substring(0, limit - 5) + " ...\n"; @@ -875,6 +937,7 @@ public class StringUtil extends StringUtilRt { } @NotNull + @Contract(pure = true) public static String trimLeading(@NotNull String string) { int index = 0; while (index < string.length() && Character.isWhitespace(string.charAt(index))) index++; @@ -882,6 +945,7 @@ public class StringUtil extends StringUtilRt { } @NotNull + @Contract(pure = true) public static String trimLeading(@NotNull String string, char symbol) { int index = 0; while (index < string.length() && string.charAt(index) == symbol) index++; @@ -889,21 +953,25 @@ public class StringUtil extends StringUtilRt { } @NotNull + @Contract(pure = true) public static String trimTrailing(@NotNull String string) { int index = string.length() - 1; while (index >= 0 && Character.isWhitespace(string.charAt(index))) index--; return string.substring(0, index + 1); } + @Contract(pure = true) public static boolean startsWithChar(@Nullable CharSequence s, char prefix) { return s != null && s.length() != 0 && s.charAt(0) == prefix; } + @Contract(pure = true) public static boolean endsWithChar(@Nullable CharSequence s, char suffix) { return StringUtilRt.endsWithChar(s, suffix); } @NotNull + @Contract(pure = true) public static String trimStart(@NotNull String s, @NonNls @NotNull String prefix) { if (s.startsWith(prefix)) { return s.substring(prefix.length()); @@ -912,6 +980,7 @@ public class StringUtil extends StringUtilRt { } @NotNull + @Contract(pure = true) public static String pluralize(@NotNull String base, int n) { if (n == 1) return base; return pluralize(base); @@ -929,45 +998,51 @@ public class StringUtil extends StringUtilRt { } } + @Contract(pure = true) public static String defaultIfEmpty(@Nullable String value, String defaultValue) { return isEmpty(value) ? defaultValue : value; } - @Contract("null -> false") + @Contract(value = "null -> false", pure = true) public static boolean isNotEmpty(@Nullable String s) { return s != null && !s.isEmpty(); } - @Contract("null -> true") + @Contract(value = "null -> true", pure=true) public static boolean isEmpty(@Nullable String s) { return s == null || s.isEmpty(); } - @Contract("null -> true") + @Contract(value = "null -> true",pure = true) public static boolean isEmpty(@Nullable CharSequence cs) { return cs == null || cs.length() == 0; } + @Contract(pure = true) public static int length(@Nullable CharSequence cs) { return cs == null ? 0 : cs.length(); } @NotNull + @Contract(pure = true) public static String notNullize(@Nullable final String s) { return notNullize(s, ""); } @NotNull + @Contract(pure = true) public static String notNullize(@Nullable final String s, @NotNull String defaultValue) { return s == null ? defaultValue : s; } @Nullable + @Contract(pure = true) public static String nullize(@Nullable final String s) { return nullize(s, false); } @Nullable + @Contract(pure = true) public static String nullize(@Nullable final String s, boolean nullizeSpaces) { if (nullizeSpaces) { if (isEmptyOrSpaces(s)) return null; @@ -978,13 +1053,13 @@ public class StringUtil extends StringUtilRt { return s; } - @Contract("null -> true") + @Contract(value = "null -> true",pure = true) // we need to keep this method to preserve backward compatibility public static boolean isEmptyOrSpaces(@Nullable String s) { return isEmptyOrSpaces(((CharSequence)s)); } - @Contract("null -> true") + @Contract(value = "null -> true", pure = true) public static boolean isEmptyOrSpaces(@Nullable CharSequence s) { if (isEmpty(s)) { return true; @@ -1003,26 +1078,31 @@ public class StringUtil extends StringUtilRt { * @param c symbol to check * @return <code>true</code> if given symbol is white space, tabulation or line feed; <code>false</code> otherwise */ + @Contract(pure = true) public static boolean isWhiteSpace(char c) { return c == '\n' || c == '\t' || c == ' '; } @NotNull + @Contract(pure = true) public static String getThrowableText(@NotNull Throwable aThrowable) { return ExceptionUtil.getThrowableText(aThrowable); } @NotNull + @Contract(pure = true) public static String getThrowableText(@NotNull Throwable aThrowable, @NonNls @NotNull final String stackFrameSkipPattern) { return ExceptionUtil.getThrowableText(aThrowable, stackFrameSkipPattern); } @Nullable + @Contract(pure = true) public static String getMessage(@NotNull Throwable e) { return ExceptionUtil.getMessage(e); } @NotNull + @Contract(pure = true) public static String repeatSymbol(final char aChar, final int count) { char[] buffer = new char[count]; Arrays.fill(buffer, aChar); @@ -1030,6 +1110,7 @@ public class StringUtil extends StringUtilRt { } @NotNull + @Contract(pure = true) public static String repeat(@NotNull String s, int count) { assert count >= 0 : count; StringBuilder sb = new StringBuilder(s.length() * count); @@ -1040,6 +1121,7 @@ public class StringUtil extends StringUtilRt { } @NotNull + @Contract(pure = true) public static List<String> splitHonorQuotes(@NotNull String s, char separator) { final List<String> result = new ArrayList<String>(); final StringBuilder builder = new StringBuilder(s.length()); @@ -1068,17 +1150,20 @@ public class StringUtil extends StringUtilRt { @NotNull + @Contract(pure = true) public static List<String> split(@NotNull String s, @NotNull String separator) { return split(s, separator, true); } @NotNull + @Contract(pure = true) public static List<String> split(@NotNull String s, @NotNull String separator, boolean excludeSeparator) { return split(s, separator, excludeSeparator, true); } @NotNull + @Contract(pure = true) public static List<String> split(@NotNull String s, @NotNull String separator, boolean excludeSeparator, boolean excludeEmptyStrings) { if (separator.isEmpty()) { @@ -1103,6 +1188,7 @@ public class StringUtil extends StringUtilRt { } @NotNull + @Contract(pure = true) public static Iterable<String> tokenize(@NotNull String s, @NotNull String separators) { final com.intellij.util.text.StringTokenizer tokenizer = new com.intellij.util.text.StringTokenizer(s, separators); return new Iterable<String>() { @@ -1130,6 +1216,7 @@ public class StringUtil extends StringUtilRt { } @NotNull + @Contract(pure = true) public static Iterable<String> tokenize(@NotNull final StringTokenizer tokenizer) { return new Iterable<String>() { @NotNull @@ -1160,6 +1247,7 @@ public class StringUtil extends StringUtilRt { * The <b>word</b> here means the maximum sub-string consisting entirely of characters which are <code>Character.isJavaIdentifierPart(c)</code>. */ @NotNull + @Contract(pure = true) public static List<String> getWordsIn(@NotNull String text) { List<String> result = null; int start = -1; @@ -1190,6 +1278,7 @@ public class StringUtil extends StringUtilRt { } @NotNull + @Contract(pure = true) public static List<TextRange> getWordIndicesIn(@NotNull String text) { List<TextRange> result = new SmartList<TextRange>(); int start = -1; @@ -1211,11 +1300,13 @@ public class StringUtil extends StringUtilRt { } @NotNull + @Contract(pure = true) public static String join(@NotNull final String[] strings, @NotNull final String separator) { return join(strings, 0, strings.length, separator); } @NotNull + @Contract(pure = true) public static String join(@NotNull final String[] strings, int startIndex, int endIndex, @NotNull final String separator) { final StringBuilder result = new StringBuilder(); for (int i = startIndex; i < endIndex; i++) { @@ -1226,6 +1317,7 @@ public class StringUtil extends StringUtilRt { } @NotNull + @Contract(pure = true) public static String[] zip(@NotNull String[] strings1, @NotNull String[] strings2, String separator) { if (strings1.length != strings2.length) throw new IllegalArgumentException(); @@ -1238,6 +1330,7 @@ public class StringUtil extends StringUtilRt { } @NotNull + @Contract(pure = true) public static String[] surround(@NotNull String[] strings1, String prefix, String suffix) { String[] result = ArrayUtil.newStringArray(strings1.length); for (int i = 0; i < result.length; i++) { @@ -1248,11 +1341,13 @@ public class StringUtil extends StringUtilRt { } @NotNull + @Contract(pure = true) public static <T> String join(@NotNull T[] items, @NotNull Function<T, String> f, @NotNull @NonNls String separator) { return join(Arrays.asList(items), f, separator); } @NotNull + @Contract(pure = true) public static <T> String join(@NotNull Collection<? extends T> items, @NotNull Function<? super T, String> f, @NotNull @NonNls String separator) { @@ -1260,6 +1355,7 @@ public class StringUtil extends StringUtilRt { return join((Iterable<? extends T>)items, f, separator); } + @Contract(pure = true) public static String join(@NotNull Iterable<?> items, @NotNull @NonNls String separator) { StringBuilder result = new StringBuilder(); for (Object item : items) { @@ -1272,6 +1368,7 @@ public class StringUtil extends StringUtilRt { } @NotNull + @Contract(pure = true) public static <T> String join(@NotNull Iterable<? extends T> items, @NotNull Function<? super T, String> f, @NotNull @NonNls String separator) { @@ -1287,6 +1384,7 @@ public class StringUtil extends StringUtilRt { } @NotNull + @Contract(pure = true) public static String join(@NotNull Collection<? extends String> strings, @NotNull String separator) { StringBuilder result = new StringBuilder(); join(strings, separator, result); @@ -1309,6 +1407,7 @@ public class StringUtil extends StringUtilRt { } @NotNull + @Contract(pure = true) public static String join(@NotNull final int[] strings, @NotNull final String separator) { final StringBuilder result = new StringBuilder(); for (int i = 0; i < strings.length; i++) { @@ -1319,6 +1418,7 @@ public class StringUtil extends StringUtilRt { } @NotNull + @Contract(pure = true) public static String join(@Nullable final String... strings) { if (strings == null || strings.length == 0) return ""; @@ -1330,12 +1430,14 @@ public class StringUtil extends StringUtilRt { } @NotNull + @Contract(pure = true) public static String stripQuotesAroundValue(@NotNull String text) { if (startsWithChar(text, '\"') || startsWithChar(text, '\'')) text = text.substring(1); if (endsWithChar(text, '\"') || endsWithChar(text, '\'')) text = text.substring(0, text.length() - 1); return text; } + @Contract(pure = true) public static boolean isQuotedString(@NotNull String text) { if (text.length() < 2) return false; return startsWithChar(text, '\"') && endsWithChar(text, '\"') @@ -1350,6 +1452,7 @@ public class StringUtil extends StringUtilRt { * @since 5.0.1 */ @NotNull + @Contract(pure = true) public static String formatFileSize(final long fileSize) { if (fileSize < 0x400) { return CommonBundle.message("format.file.size.bytes", fileSize); @@ -1365,6 +1468,7 @@ public class StringUtil extends StringUtilRt { } @NotNull + @Contract(pure = true) public static String formatDuration(long duration) { final long minutes = duration / 60000; final long seconds = ((duration + 500L) % 60000) / 1000; @@ -1375,6 +1479,7 @@ public class StringUtil extends StringUtilRt { } @NotNull + @Contract(pure = true) private static String formatMinor(long number) { if (number > 0L && number <= 9L) { return "0" + number; @@ -1391,6 +1496,7 @@ public class StringUtil extends StringUtilRt { */ @SuppressWarnings({"HardCodedStringLiteral"}) @Nullable + @Contract(pure = true) public static String unpluralize(@NotNull final String name) { if (name.endsWith("sses") || name.endsWith("shes") || name.endsWith("ches") || name.endsWith("xes")) { //? return name.substring(0, name.length() - 2); @@ -1430,6 +1536,7 @@ public class StringUtil extends StringUtilRt { } @Nullable + @Contract(pure = true) private static String stripEnding(@NotNull String name, @NotNull String ending) { if (name.endsWith(ending)) { if (name.equals(ending)) return name; // do not return empty string @@ -1438,6 +1545,7 @@ public class StringUtil extends StringUtilRt { return null; } + @Contract(pure = true) public static boolean containsAlphaCharacters(@NotNull String value) { for (int i = 0; i < value.length(); i++) { if (Character.isLetter(value.charAt(i))) return true; @@ -1445,6 +1553,7 @@ public class StringUtil extends StringUtilRt { return false; } + @Contract(pure = true) public static boolean containsAnyChar(@NotNull final String value, @NotNull final String chars) { if (chars.length() > value.length()) { return containsAnyChar(value, chars, 0, value.length()); @@ -1454,6 +1563,7 @@ public class StringUtil extends StringUtilRt { } } + @Contract(pure = true) public static boolean containsAnyChar(@NotNull final String value, @NotNull final String chars, final int start, final int end) { @@ -1466,6 +1576,7 @@ public class StringUtil extends StringUtilRt { return false; } + @Contract(pure = true) public static boolean containsChar(@NotNull final String value, final char ch) { return value.indexOf(ch) >= 0; } @@ -1473,7 +1584,7 @@ public class StringUtil extends StringUtilRt { /** * @deprecated use #capitalize(String) */ - @Contract("null -> null; !null -> !null") + @Contract(value = "null -> null; !null -> !null", pure = true) public static String firstLetterToUpperCase(@Nullable final String displayString) { if (displayString == null || displayString.isEmpty()) return displayString; char firstChar = displayString.charAt(0); @@ -1494,6 +1605,7 @@ public class StringUtil extends StringUtilRt { * @return stripped string e.g. "mystring" */ @NotNull + @Contract(pure = true) public static String strip(@NotNull final String s, @NotNull final CharFilter filter) { final StringBuilder result = new StringBuilder(s.length()); for (int i = 0; i < s.length(); i++) { @@ -1506,11 +1618,13 @@ public class StringUtil extends StringUtilRt { } @NotNull + @Contract(pure = true) public static List<String> findMatches(@NotNull String s, @NotNull Pattern pattern) { return findMatches(s, pattern, 1); } @NotNull + @Contract(pure = true) public static List<String> findMatches(@NotNull String s, @NotNull Pattern pattern, int groupIndex) { List<String> result = new SmartList<String>(); Matcher m = pattern.matcher(s); @@ -1530,6 +1644,7 @@ public class StringUtil extends StringUtilRt { * @param filter search filter * @return position of the first character accepted or -1 if not found */ + @Contract(pure = true) public static int findFirst(@NotNull final CharSequence s, @NotNull CharFilter filter) { for (int i = 0; i < s.length(); i++) { char ch = s.charAt(i); @@ -1541,18 +1656,22 @@ public class StringUtil extends StringUtilRt { } @NotNull + @Contract(pure = true) public static String replaceSubstring(@NotNull String string, @NotNull TextRange range, @NotNull String replacement) { return range.replace(string, replacement); } + @Contract(pure = true) public static boolean startsWithWhitespace(@NotNull String text) { return !text.isEmpty() && Character.isWhitespace(text.charAt(0)); } + @Contract(pure = true) public static boolean isChar(CharSequence seq, int index, char c) { return index >= 0 && index < seq.length() && seq.charAt(index) == c; } + @Contract(pure = true) public static boolean startsWith(@NotNull CharSequence text, @NotNull CharSequence prefix) { int l1 = text.length(); int l2 = prefix.length(); @@ -1565,6 +1684,7 @@ public class StringUtil extends StringUtilRt { return true; } + @Contract(pure = true) public static boolean startsWith(@NotNull CharSequence text, int startIndex, @NotNull CharSequence prefix) { int l1 = text.length() - startIndex; int l2 = prefix.length(); @@ -1577,6 +1697,7 @@ public class StringUtil extends StringUtilRt { return true; } + @Contract(pure = true) public static boolean endsWith(@NotNull CharSequence text, @NotNull CharSequence suffix) { int l1 = text.length(); int l2 = suffix.length(); @@ -1590,10 +1711,12 @@ public class StringUtil extends StringUtilRt { } @NotNull + @Contract(pure = true) public static String commonPrefix(@NotNull String s1, @NotNull String s2) { return s1.substring(0, commonPrefixLength(s1, s2)); } + @Contract(pure = true) public static int commonPrefixLength(@NotNull CharSequence s1, @NotNull CharSequence s2) { int i; int minLength = Math.min(s1.length(), s2.length()); @@ -1606,10 +1729,12 @@ public class StringUtil extends StringUtilRt { } @NotNull + @Contract(pure = true) public static String commonSuffix(@NotNull String s1, @NotNull String s2) { return s1.substring(s1.length() - commonSuffixLength(s1, s2)); } + @Contract(pure = true) public static int commonSuffixLength(@NotNull CharSequence s1, @NotNull CharSequence s2) { int s1Length = s1.length(); int s2Length = s2.length(); @@ -1633,10 +1758,12 @@ public class StringUtil extends StringUtilRt { * @return <code>true</code> if given symbol is contained at the target range of the given char sequence; * <code>false</code> otherwise */ + @Contract(pure = true) public static boolean contains(@NotNull CharSequence s, int start, int end, char c) { return indexOf(s, c, start, end) >= 0; } + @Contract(pure = true) public static boolean containsWhitespaces(@Nullable CharSequence s) { if (s == null) return false; @@ -1646,14 +1773,17 @@ public class StringUtil extends StringUtilRt { return false; } + @Contract(pure = true) public static int indexOf(@NotNull CharSequence s, char c) { return indexOf(s, c, 0, s.length()); } + @Contract(pure = true) public static int indexOf(@NotNull CharSequence s, char c, int start) { return indexOf(s, c, start, s.length()); } + @Contract(pure = true) public static int indexOf(@NotNull CharSequence s, char c, int start, int end) { for (int i = start; i < end; i++) { if (s.charAt(i) == c) return i; @@ -1661,10 +1791,12 @@ public class StringUtil extends StringUtilRt { return -1; } + @Contract(pure = true) public static boolean contains(@NotNull CharSequence sequence, @NotNull CharSequence infix) { return indexOf(sequence, infix) >= 0; } - + + @Contract(pure = true) public static int indexOf(@NotNull CharSequence sequence, @NotNull CharSequence infix) { for (int i = 0; i < sequence.length() - infix.length(); i++) { if (startsWith(sequence, i, infix)) { @@ -1674,6 +1806,7 @@ public class StringUtil extends StringUtilRt { return -1; } + @Contract(pure = true) public static int indexOf(@NotNull CharSequence s, char c, int start, int end, boolean caseSensitive) { for (int i = start; i < end; i++) { if (charsMatch(s.charAt(i), c, !caseSensitive)) return i; @@ -1681,6 +1814,7 @@ public class StringUtil extends StringUtilRt { return -1; } + @Contract(pure = true) public static int indexOf(@NotNull char[] s, char c, int start, int end, boolean caseSensitive) { for (int i = start; i < end; i++) { if (charsMatch(s[i], c, !caseSensitive)) return i; @@ -1688,24 +1822,29 @@ public class StringUtil extends StringUtilRt { return -1; } + @Contract(pure = true) public static int indexOfSubstringEnd(@NotNull String text, @NotNull String subString) { int i = text.indexOf(subString); if (i == -1) return -1; return i + subString.length(); } + @Contract(pure = true) public static int indexOfAny(@NotNull final String s, @NotNull final String chars) { return indexOfAny(s, chars, 0, s.length()); } + @Contract(pure = true) public static int indexOfAny(@NotNull final CharSequence s, @NotNull final String chars) { return indexOfAny(s, chars, 0, s.length()); } + @Contract(pure = true) public static int indexOfAny(@NotNull final String s, @NotNull final String chars, final int start, final int end) { return indexOfAny((CharSequence)s, chars, start, end); } + @Contract(pure = true) public static int indexOfAny(@NotNull final CharSequence s, @NotNull final String chars, final int start, final int end) { for (int i = start; i < end; i++) { if (containsChar(chars, s.charAt(i))) return i; @@ -1714,6 +1853,7 @@ public class StringUtil extends StringUtilRt { } @Nullable + @Contract(pure = true) public static String substringBefore(@NotNull String text, @NotNull String subString) { int i = text.indexOf(subString); if (i == -1) return null; @@ -1721,6 +1861,7 @@ public class StringUtil extends StringUtilRt { } @Nullable + @Contract(pure = true) public static String substringAfter(@NotNull String text, @NotNull String subString) { int i = text.indexOf(subString); if (i == -1) return null; @@ -1737,26 +1878,31 @@ public class StringUtil extends StringUtilRt { * @return index of the last occurrence of the given symbol at the target sub-sequence of the given text if any; * <code>-1</code> otherwise */ + @Contract(pure = true) public static int lastIndexOf(@NotNull CharSequence s, char c, int start, int end) { return StringUtilRt.lastIndexOf(s, c, start, end); } @NotNull + @Contract(pure = true) public static String first(@NotNull String text, final int maxLength, final boolean appendEllipsis) { return text.length() > maxLength ? text.substring(0, maxLength) + (appendEllipsis ? "..." : "") : text; } @NotNull + @Contract(pure = true) public static CharSequence first(@NotNull CharSequence text, final int length, final boolean appendEllipsis) { return text.length() > length ? text.subSequence(0, length) + (appendEllipsis ? "..." : "") : text; } @NotNull + @Contract(pure = true) public static CharSequence last(@NotNull CharSequence text, final int length, boolean prependEllipsis) { return text.length() > length ? (prependEllipsis ? "..." : "") + text.subSequence(text.length() - length, text.length()) : text; } @NotNull + @Contract(pure = true) public static String escapeChar(@NotNull final String str, final char character) { final StringBuilder buf = new StringBuilder(str); escapeChar(buf, character); @@ -1772,6 +1918,7 @@ public class StringUtil extends StringUtilRt { } @NotNull + @Contract(pure = true) public static String escapeQuotes(@NotNull final String str) { return escapeChar(str, '"'); } @@ -1781,11 +1928,13 @@ public class StringUtil extends StringUtilRt { } @NotNull + @Contract(pure = true) public static String escapeSlashes(@NotNull final String str) { return escapeChar(str, '/'); } @NotNull + @Contract(pure = true) public static String escapeBackSlashes(@NotNull final String str) { return escapeChar(str, '\\'); } @@ -1795,6 +1944,7 @@ public class StringUtil extends StringUtilRt { } @NotNull + @Contract(pure = true) public static String unescapeSlashes(@NotNull final String str) { final StringBuilder buf = new StringBuilder(str.length()); unescapeSlashes(buf, str); @@ -1826,6 +1976,7 @@ public class StringUtil extends StringUtilRt { } @NotNull + @Contract(pure = true) public static String wrapWithDoubleQuote(@NotNull String str) { return '\"' + str + "\""; } @@ -1833,25 +1984,27 @@ public class StringUtil extends StringUtilRt { @NonNls private static final String[] REPLACES_REFS = {"<", ">", "&", "'", """}; @NonNls private static final String[] REPLACES_DISP = {"<", ">", "&", "'", "\""}; - @Contract("null -> null; !null -> !null") + @Contract(value = "null -> null; !null -> !null",pure = true) public static String unescapeXml(@Nullable final String text) { if (text == null) return null; return replace(text, REPLACES_REFS, REPLACES_DISP); } - @Contract("null -> null; !null -> !null") + @Contract(value = "null -> null; !null -> !null",pure = true) public static String escapeXml(@Nullable final String text) { if (text == null) return null; return replace(text, REPLACES_DISP, REPLACES_REFS); } @NotNull - public static String htmlEmphasize(String text) { + @Contract(pure = true) + public static String htmlEmphasize(@NotNull String text) { return "<b><code>" + escapeXml(text) + "</code></b>"; } @NotNull + @Contract(pure = true) public static String escapeToRegexp(@NotNull String text) { final StringBuilder result = new StringBuilder(text.length()); return escapeToRegexp(text, result).toString(); @@ -1875,6 +2028,7 @@ public class StringUtil extends StringUtilRt { return builder; } + @Contract(pure = true) public static boolean isNotEscapedBackslash(@NotNull char[] chars, int startOffset, int backslashOffset) { if (chars[backslashOffset] != '\\') { return false; @@ -1891,6 +2045,7 @@ public class StringUtil extends StringUtilRt { return !escaped; } + @Contract(pure = true) public static boolean isNotEscapedBackslash(@NotNull CharSequence text, int startOffset, int backslashOffset) { if (text.charAt(backslashOffset) != '\\') { return false; @@ -1908,6 +2063,7 @@ public class StringUtil extends StringUtilRt { } @NotNull + @Contract(pure = true) public static String replace(@NotNull String text, @NotNull String[] from, @NotNull String[] to) { final StringBuilder result = new StringBuilder(text.length()); replace: @@ -1929,6 +2085,7 @@ public class StringUtil extends StringUtilRt { } @NotNull + @Contract(pure = true) public static String[] filterEmptyStrings(@NotNull String[] strings) { int emptyCount = 0; for (String string : strings) { @@ -1946,14 +2103,17 @@ public class StringUtil extends StringUtilRt { return result; } + @Contract(pure = true) public static int countNewLines(@NotNull CharSequence text) { return countChars(text, '\n'); } + @Contract(pure = true) public static int countChars(@NotNull CharSequence text, char c) { return countChars(text, c, 0, false); } + @Contract(pure = true) public static int countChars(@NotNull CharSequence text, char c, int offset, boolean continuous) { int count = 0; for (int i = offset; i < text.length(); ++i) { @@ -1968,6 +2128,7 @@ public class StringUtil extends StringUtilRt { } @NotNull + @Contract(pure = true) public static String capitalsOnly(@NotNull String s) { StringBuilder b = new StringBuilder(); for (int i = 0; i < s.length(); i++) { @@ -1984,6 +2145,7 @@ public class StringUtil extends StringUtilRt { * @return {@code null} if any of given Strings is {@code null}. */ @Nullable + @Contract(pure = true) public static String joinOrNull(@NotNull String... args) { StringBuilder r = new StringBuilder(); for (String arg : args) { @@ -1994,6 +2156,7 @@ public class StringUtil extends StringUtilRt { } @Nullable + @Contract(pure = true) public static String getPropertyName(@NonNls @NotNull String methodName) { if (methodName.startsWith("get")) { return Introspector.decapitalize(methodName.substring(3)); @@ -2009,14 +2172,17 @@ public class StringUtil extends StringUtilRt { } } + @Contract(pure = true) public static boolean isJavaIdentifierStart(char c) { return c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || Character.isJavaIdentifierStart(c); } + @Contract(pure = true) public static boolean isJavaIdentifierPart(char c) { return c >= '0' && c <= '9' || isJavaIdentifierStart(c); } + @Contract(pure = true) public static boolean isJavaIdentifier(@NotNull String text) { int len = text.length(); if (len == 0) return false; @@ -2038,6 +2204,7 @@ public class StringUtil extends StringUtilRt { * @return an escaped string */ @NotNull + @Contract(pure = true) public static String escapeProperty(@NotNull String input, final boolean isKey) { final StringBuilder escaped = new StringBuilder(input.length()); for (int i = 0; i < input.length(); i++) { @@ -2087,6 +2254,7 @@ public class StringUtil extends StringUtilRt { return escaped.toString(); } + @Contract(pure = true) public static String getQualifiedName(@Nullable String packageName, String className) { if (packageName == null || packageName.isEmpty()) { return className; @@ -2094,6 +2262,7 @@ public class StringUtil extends StringUtilRt { return packageName + '.' + className; } + @Contract(pure = true) public static int compareVersionNumbers(@Nullable String v1, @Nullable String v2) { // todo duplicates com.intellij.util.text.VersionComparatorUtil.compare // todo please refactor next time you make changes here @@ -2147,6 +2316,7 @@ public class StringUtil extends StringUtilRt { } } + @Contract(pure = true) public static int getOccurrenceCount(@NotNull String text, final char c) { int res = 0; int i = 0; @@ -2163,6 +2333,7 @@ public class StringUtil extends StringUtilRt { return res; } + @Contract(pure = true) public static int getOccurrenceCount(@NotNull String text, @NotNull String s) { int res = 0; int i = 0; @@ -2180,6 +2351,7 @@ public class StringUtil extends StringUtilRt { } @NotNull + @Contract(pure = true) public static String fixVariableNameDerivedFromPropertyName(@NotNull String name) { if (isEmptyOrSpaces(name)) return name; char c = name.charAt(0); @@ -2190,6 +2362,7 @@ public class StringUtil extends StringUtilRt { } @NotNull + @Contract(pure = true) public static String sanitizeJavaIdentifier(@NotNull String name) { final StringBuilder result = new StringBuilder(name.length()); @@ -2236,6 +2409,7 @@ public class StringUtil extends StringUtilRt { } @NotNull + @Contract(pure = true) public static String tail(@NotNull String s, final int idx) { return idx >= s.length() ? "" : s.substring(idx, s.length()); } @@ -2247,6 +2421,7 @@ public class StringUtil extends StringUtilRt { * @return array of strings */ @NotNull + @Contract(pure = true) public static String[] splitByLines(@NotNull String string) { return splitByLines(string, true); } @@ -2259,11 +2434,13 @@ public class StringUtil extends StringUtilRt { * @return array of strings */ @NotNull + @Contract(pure = true) public static String[] splitByLines(@NotNull String string, boolean excludeEmptyStrings) { return (excludeEmptyStrings ? EOL_SPLIT_PATTERN : EOL_SPLIT_PATTERN_WITH_EMPTY).split(string); } @NotNull + @Contract(pure = true) public static String[] splitByLinesDontTrim(@NotNull String string) { return EOL_SPLIT_DONT_TRIM_PATTERN.split(string); } @@ -2280,14 +2457,16 @@ public class StringUtil extends StringUtilRt { * \r<br> * </blockquote> * will return the following array: foo\r\n, \n, bar\n, \r\n, baz\r, \r - * + * */ @NotNull + @Contract(pure = true) public static String[] splitByLinesKeepSeparators(@NotNull String string) { return EOL_SPLIT_KEEP_SEPARATORS.split(string); } @NotNull + @Contract(pure = true) public static List<Pair<String, Integer>> getWordsWithOffset(@NotNull String s) { List<Pair<String, Integer>> res = ContainerUtil.newArrayList(); s += " "; @@ -2315,10 +2494,12 @@ public class StringUtil extends StringUtilRt { * Implementation of "Sorting for Humans: Natural Sort Order": * http://www.codinghorror.com/blog/2007/12/sorting-for-humans-natural-sort-order.html */ + @Contract(pure = true) public static int naturalCompare(@Nullable String string1, @Nullable String string2) { return naturalCompare(string1, string2, false); } + @Contract(pure = true) private static int naturalCompare(@Nullable String string1, @Nullable String string2, boolean caseSensitive) { //noinspection StringEquality if (string1 == string2) { @@ -2333,7 +2514,8 @@ public class StringUtil extends StringUtilRt { final int string1Length = string1.length(); final int string2Length = string2.length(); - int i = 0, j = 0; + int i = 0; + int j = 0; for (; i < string1Length && j < string2Length; i++, j++) { char ch1 = string1.charAt(i); char ch2 = string2.charAt(j); @@ -2404,10 +2586,12 @@ public class StringUtil extends StringUtilRt { return string1Length - string2Length; } + @Contract(pure = true) public static boolean isDecimalDigit(char c) { return c >= '0' && c <= '9'; } + @Contract(pure = true) public static int compare(@Nullable String s1, @Nullable String s2, boolean ignoreCase) { //noinspection StringEquality if (s1 == s2) return 0; @@ -2416,15 +2600,18 @@ public class StringUtil extends StringUtilRt { return ignoreCase ? s1.compareToIgnoreCase(s2) : s1.compareTo(s2); } + @Contract(pure = true) public static int comparePairs(@Nullable String s1, @Nullable String t1, @Nullable String s2, @Nullable String t2, boolean ignoreCase) { final int compare = compare(s1, s2, ignoreCase); return compare != 0 ? compare : compare(t1, t2, ignoreCase); } + @Contract(pure = true) public static int hashCode(@NotNull CharSequence s) { return stringHashCode(s); } + @Contract(pure = true) public static boolean equals(@Nullable CharSequence s1, @Nullable CharSequence s2) { if (s1 == null ^ s2 == null) { return false; @@ -2445,6 +2632,7 @@ public class StringUtil extends StringUtilRt { return true; } + @Contract(pure = true) public static boolean equalsIgnoreCase(@Nullable CharSequence s1, @Nullable CharSequence s2) { if (s1 == null ^ s2 == null) { return false; @@ -2465,6 +2653,7 @@ public class StringUtil extends StringUtilRt { return true; } + @Contract(pure = true) public static int compare(char c1, char c2, boolean ignoreCase) { // duplicating String.equalsIgnoreCase logic int d = c1 - c2; @@ -2488,11 +2677,13 @@ public class StringUtil extends StringUtilRt { return d; } + @Contract(pure = true) public static boolean charsMatch(char c1, char c2, boolean ignoreCase) { return compare(c1, c2, ignoreCase) == 0; } @NotNull + @Contract(pure = true) public static String formatLinks(@NotNull String message) { Pattern linkPattern = Pattern.compile("http://[a-zA-Z0-9\\./\\-\\+]+"); StringBuffer result = new StringBuffer(); @@ -2504,25 +2695,30 @@ public class StringUtil extends StringUtilRt { return result.toString(); } + @Contract(pure = true) public static boolean isHexDigit(char c) { return '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F'; } + @Contract(pure = true) public static boolean isOctalDigit(char c) { return '0' <= c && c <= '7'; } @NotNull + @Contract(pure = true) public static String shortenTextWithEllipsis(@NotNull final String text, final int maxLength, final int suffixLength) { return shortenTextWithEllipsis(text, maxLength, suffixLength, false); } @NotNull + @Contract(pure = true) public static String trimMiddle(@NotNull String text, int maxLength) { return shortenTextWithEllipsis(text, maxLength, maxLength >> 1, true); } @NotNull + @Contract(pure = true) public static String shortenTextWithEllipsis(@NotNull final String text, final int maxLength, final int suffixLength, @@ -2539,6 +2735,7 @@ public class StringUtil extends StringUtilRt { } @NotNull + @Contract(pure = true) public static String shortenTextWithEllipsis(@NotNull final String text, final int maxLength, final int suffixLength, @@ -2548,47 +2745,57 @@ public class StringUtil extends StringUtilRt { } @NotNull + @Contract(pure = true) public static String shortenPathWithEllipsis(@NotNull final String path, final int maxLength, boolean useEllipsisSymbol) { return shortenTextWithEllipsis(path, maxLength, (int)(maxLength * 0.7), useEllipsisSymbol); } @NotNull + @Contract(pure = true) public static String shortenPathWithEllipsis(@NotNull final String path, final int maxLength) { return shortenPathWithEllipsis(path, maxLength, false); } + @Contract(pure = true) public static boolean charsEqual(char a, char b, boolean ignoreCase) { return ignoreCase ? charsEqualIgnoreCase(a, b) : a == b; } + @Contract(pure = true) public static boolean charsEqualIgnoreCase(char a, char b) { return StringUtilRt.charsEqualIgnoreCase(a, b); } + @Contract(pure = true) public static char toUpperCase(char a) { return StringUtilRt.toUpperCase(a); } @NotNull + @Contract(pure = true) public static String toUpperCase(@NotNull String a) { return StringUtilRt.toUpperCase(a); } + @Contract(pure = true) public static char toLowerCase(final char a) { return StringUtilRt.toLowerCase(a); } @NotNull + @Contract(pure = true) public static String convertLineSeparators(@NotNull String text) { return StringUtilRt.convertLineSeparators(text); } @NotNull + @Contract(pure = true) public static String convertLineSeparators(@NotNull String text, boolean keepCarriageReturn) { return StringUtilRt.convertLineSeparators(text, keepCarriageReturn); } @NotNull + @Contract(pure = true) public static String convertLineSeparators(@NotNull String text, @NotNull String newSeparator) { return StringUtilRt.convertLineSeparators(text, newSeparator); } @@ -2606,34 +2813,41 @@ public class StringUtil extends StringUtilRt { return StringUtilRt.convertLineSeparators(text, newSeparator, offsetsToKeep, keepCarriageReturn); } + @Contract(pure = true) public static int parseInt(final String string, final int defaultValue) { return StringUtilRt.parseInt(string, defaultValue); } + @Contract(pure = true) public static double parseDouble(final String string, final double defaultValue) { return StringUtilRt.parseDouble(string, defaultValue); } + @Contract(pure = true) public static boolean parseBoolean(String string, final boolean defaultValue) { return StringUtilRt.parseBoolean(string, defaultValue); } @NotNull + @Contract(pure = true) public static String getShortName(@NotNull Class aClass) { return StringUtilRt.getShortName(aClass); } @NotNull + @Contract(pure = true) public static String getShortName(@NotNull String fqName) { return StringUtilRt.getShortName(fqName); } @NotNull + @Contract(pure = true) public static String getShortName(@NotNull String fqName, char separator) { return StringUtilRt.getShortName(fqName, separator); } @NotNull + @Contract(pure = true) public static CharSequence newBombedCharSequence(@NotNull CharSequence sequence, long delay) { final long myTime = System.currentTimeMillis() + delay; return new BombedCharSequence(sequence) { @@ -2655,23 +2869,17 @@ public class StringUtil extends StringUtilRt { return false; } - private static boolean trimStart(@NotNull StringBuilder buffer, @NotNull CharSequence start) { - if (startsWith(buffer, start)) { - buffer.delete(0, start.length()); - return true; - } - return false; - } - /** * Say smallPart = "op" and bigPart="open". Method returns true for "Ope" and false for "ops" */ + @Contract(pure = true) public static boolean isBetween(@NotNull String string, @NotNull String smallPart, @NotNull String bigPart) { final String s = string.toLowerCase(); return s.startsWith(smallPart.toLowerCase()) && bigPart.toLowerCase().startsWith(s); } - public static String getShortened(String s, int maxWidth) { + @Contract(pure = true) + public static String getShortened(@NotNull String s, int maxWidth) { int length = s.length(); if (isEmpty(s) || length <= maxWidth) return s; ArrayList<String> words = new ArrayList<String>(); diff --git a/platform/util/src/com/intellij/util/ArrayUtil.java b/platform/util/src/com/intellij/util/ArrayUtil.java index d0419de9e820..0dcfdb307ae0 100644 --- a/platform/util/src/com/intellij/util/ArrayUtil.java +++ b/platform/util/src/com/intellij/util/ArrayUtil.java @@ -18,6 +18,7 @@ package com.intellij.util; import com.intellij.openapi.util.Comparing; import com.intellij.util.text.CharArrayCharSequence; import gnu.trove.Equality; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -64,6 +65,7 @@ public class ArrayUtil extends ArrayUtilRt { private ArrayUtil() { } @NotNull + @Contract(pure=true) public static byte[] realloc(@NotNull byte[] array, final int newSize) { if (newSize == 0) { return EMPTY_BYTE_ARRAY; @@ -79,6 +81,7 @@ public class ArrayUtil extends ArrayUtilRt { return result; } @NotNull + @Contract(pure=true) public static boolean[] realloc(@NotNull boolean[] array, final int newSize) { if (newSize == 0) { return EMPTY_BOOLEAN_ARRAY; @@ -95,6 +98,7 @@ public class ArrayUtil extends ArrayUtilRt { } @NotNull + @Contract(pure=true) public static int[] realloc(@NotNull int[] array, final int newSize) { if (newSize == 0) { return EMPTY_INT_ARRAY; @@ -110,6 +114,7 @@ public class ArrayUtil extends ArrayUtilRt { return result; } @NotNull + @Contract(pure=true) public static <T> T[] realloc(@NotNull T[] array, final int newSize, @NotNull ArrayFactory<T> factory) { final int oldSize = array.length; if (oldSize == newSize) { @@ -126,12 +131,14 @@ public class ArrayUtil extends ArrayUtilRt { } @NotNull + @Contract(pure=true) public static int[] append(@NotNull int[] array, int value) { array = realloc(array, array.length + 1); array[array.length - 1] = value; return array; } @NotNull + @Contract(pure=true) public static int[] insert(@NotNull int[] array, int index, int value) { int[] result = new int[array.length + 1]; System.arraycopy(array, 0, result, 0, index); @@ -141,12 +148,14 @@ public class ArrayUtil extends ArrayUtilRt { } @NotNull + @Contract(pure=true) public static byte[] append(@NotNull byte[] array, byte value) { array = realloc(array, array.length + 1); array[array.length - 1] = value; return array; } @NotNull + @Contract(pure=true) public static boolean[] append(@NotNull boolean[] array, boolean value) { array = realloc(array, array.length + 1); array[array.length - 1] = value; @@ -154,6 +163,7 @@ public class ArrayUtil extends ArrayUtilRt { } @NotNull + @Contract(pure=true) public static char[] realloc(@NotNull char[] array, final int newSize) { if (newSize == 0) { return EMPTY_CHAR_ARRAY; @@ -170,12 +180,14 @@ public class ArrayUtil extends ArrayUtilRt { } @NotNull + @Contract(pure=true) public static <T> T[] toObjectArray(@NotNull Collection<T> collection, @NotNull Class<T> aClass) { @SuppressWarnings("unchecked") T[] array = (T[])Array.newInstance(aClass, collection.size()); return collection.toArray(array); } @NotNull + @Contract(pure=true) public static <T> T[] toObjectArray(@NotNull Class<T> aClass, @NotNull Object... source) { @SuppressWarnings("unchecked") T[] array = (T[])Array.newInstance(aClass, source.length); System.arraycopy(source, 0, array, 0, array.length); @@ -183,6 +195,7 @@ public class ArrayUtil extends ArrayUtilRt { } @NotNull + @Contract(pure=true) public static Object[] toObjectArray(@NotNull Collection<?> collection) { if (collection.isEmpty()) return EMPTY_OBJECT_ARRAY; //noinspection SSBasedInspection @@ -190,6 +203,7 @@ public class ArrayUtil extends ArrayUtilRt { } @NotNull + @Contract(pure=true) public static int[] toIntArray(@NotNull Collection<Integer> list) { int[] ret = newIntArray(list.size()); int i = 0; @@ -200,6 +214,7 @@ public class ArrayUtil extends ArrayUtilRt { } @NotNull + @Contract(pure=true) public static <T> T[] mergeArrays(@NotNull T[] a1, @NotNull T[] a2) { if (a1.length == 0) { return a2; @@ -219,6 +234,7 @@ public class ArrayUtil extends ArrayUtilRt { } @NotNull + @Contract(pure=true) public static <T> T[] mergeCollections(@NotNull Collection<? extends T> c1, @NotNull Collection<? extends T> c2, @NotNull ArrayFactory<T> factory) { T[] res = factory.create(c1.size() + c2.size()); @@ -236,6 +252,7 @@ public class ArrayUtil extends ArrayUtilRt { } @NotNull + @Contract(pure=true) public static <T> T[] mergeArrays(@NotNull T[] a1, @NotNull T[] a2, @NotNull ArrayFactory<T> factory) { if (a1.length == 0) { return a2; @@ -250,11 +267,13 @@ public class ArrayUtil extends ArrayUtilRt { } @NotNull + @Contract(pure=true) public static String[] mergeArrays(@NotNull String[] a1, @NotNull String... a2) { return mergeArrays(a1, a2, STRING_ARRAY_FACTORY); } @NotNull + @Contract(pure=true) public static int[] mergeArrays(@NotNull int[] a1, @NotNull int[] a2) { if (a1.length == 0) { return a2; @@ -269,6 +288,7 @@ public class ArrayUtil extends ArrayUtilRt { } @NotNull + @Contract(pure=true) public static byte[] mergeArrays(@NotNull byte[] a1, @NotNull byte[] a2) { if (a1.length == 0) { return a2; @@ -292,6 +312,7 @@ public class ArrayUtil extends ArrayUtilRt { * @return destination array */ @NotNull + @Contract(pure=true) public static <T> T[] mergeArrayAndCollection(@NotNull T[] array, @NotNull Collection<T> collection, @NotNull final ArrayFactory<T> factory) { @@ -326,16 +347,19 @@ public class ArrayUtil extends ArrayUtilRt { * @return new array */ @NotNull + @Contract(pure=true) public static <T> T[] append(@NotNull final T[] src, @Nullable final T element) { return append(src, element, (Class<T>)src.getClass().getComponentType()); } @NotNull + @Contract(pure=true) public static <T> T[] prepend(final T element, @NotNull final T[] array) { return prepend(element, array, (Class<T>)array.getClass().getComponentType()); } @NotNull + @Contract(pure=true) public static <T> T[] prepend(T element, @NotNull T[] array, @NotNull Class<T> type) { int length = array.length; T[] result = (T[])Array.newInstance(type, length + 1); @@ -345,6 +369,7 @@ public class ArrayUtil extends ArrayUtilRt { } @NotNull + @Contract(pure=true) public static byte[] prepend(byte element, @NotNull byte[] array) { int length = array.length; final byte[] result = new byte[length + 1]; @@ -353,8 +378,8 @@ public class ArrayUtil extends ArrayUtilRt { return result; } + @Contract(pure=true) public static <T> T[] append(@NotNull final T[] src, final T element, @NotNull ArrayFactory<T> factory) { - int length = src.length; T[] result = factory.create(length + 1); System.arraycopy(src, 0, result, 0, length); @@ -363,6 +388,7 @@ public class ArrayUtil extends ArrayUtilRt { } @NotNull + @Contract(pure=true) public static <T> T[] append(@NotNull T[] src, @Nullable final T element, @NotNull Class<T> componentType) { int length = src.length; T[] result = (T[])Array.newInstance(componentType, length + 1); @@ -379,6 +405,7 @@ public class ArrayUtil extends ArrayUtilRt { * @return modified array. */ @NotNull + @Contract(pure=true) public static <T> T[] remove(@NotNull final T[] src, int idx) { int length = src.length; if (idx < 0 || idx >= length) { @@ -391,6 +418,7 @@ public class ArrayUtil extends ArrayUtilRt { } @NotNull + @Contract(pure=true) public static <T> T[] remove(@NotNull final T[] src, int idx, @NotNull ArrayFactory<T> factory) { int length = src.length; if (idx < 0 || idx >= length) { @@ -403,6 +431,7 @@ public class ArrayUtil extends ArrayUtilRt { } @NotNull + @Contract(pure=true) public static <T> T[] remove(@NotNull final T[] src, T element) { final int idx = find(src, element); if (idx == -1) return src; @@ -411,6 +440,7 @@ public class ArrayUtil extends ArrayUtilRt { } @NotNull + @Contract(pure=true) public static <T> T[] remove(@NotNull final T[] src, T element, @NotNull ArrayFactory<T> factory) { final int idx = find(src, element); if (idx == -1) return src; @@ -419,6 +449,7 @@ public class ArrayUtil extends ArrayUtilRt { } @NotNull + @Contract(pure=true) public static int[] remove(@NotNull final int[] src, int idx) { int length = src.length; if (idx < 0 || idx >= length) { @@ -430,6 +461,7 @@ public class ArrayUtil extends ArrayUtilRt { return result; } @NotNull + @Contract(pure=true) public static short[] remove(@NotNull final short[] src, int idx) { int length = src.length; if (idx < 0 || idx >= length) { @@ -441,6 +473,7 @@ public class ArrayUtil extends ArrayUtilRt { return result; } + @Contract(pure=true) public static <T> int lastIndexOf(@NotNull final T[] src, final T obj) { for (int i = src.length - 1; i >= 0; i--) { final T o = src[i]; @@ -458,14 +491,17 @@ public class ArrayUtil extends ArrayUtilRt { return -1; } + @Contract(pure=true) public static int find(@NotNull int[] src, int obj) { return indexOf(src, obj); } + @Contract(pure=true) public static <T> int find(@NotNull final T[] src, final T obj) { return ArrayUtilRt.find(src, obj); } + @Contract(pure=true) public static boolean startsWith(@NotNull byte[] array, @NotNull byte[] prefix) { if (array == prefix) { return true; @@ -484,6 +520,7 @@ public class ArrayUtil extends ArrayUtilRt { return true; } + @Contract(pure=true) public static <E> boolean startsWith(@NotNull E[] array, @NotNull E[] subArray) { if (array == subArray) { return true; @@ -502,6 +539,7 @@ public class ArrayUtil extends ArrayUtilRt { return true; } + @Contract(pure=true) public static boolean startsWith(@NotNull byte[] array, int start, @NotNull byte[] subArray) { int length = subArray.length; if (array.length - start < length) { @@ -517,6 +555,7 @@ public class ArrayUtil extends ArrayUtilRt { return true; } + @Contract(pure=true) public static <T> boolean equals(@NotNull T[] a1, @NotNull T[] a2, @NotNull Equality<? super T> comparator) { if (a1 == a2) { return true; @@ -535,6 +574,7 @@ public class ArrayUtil extends ArrayUtilRt { return true; } + @Contract(pure=true) public static <T> boolean equals(@NotNull T[] a1, @NotNull T[] a2, @NotNull Comparator<? super T> comparator) { if (a1 == a2) { return true; @@ -553,6 +593,7 @@ public class ArrayUtil extends ArrayUtilRt { } @NotNull + @Contract(pure=true) public static <T> T[] reverseArray(@NotNull T[] array) { T[] newArray = array.clone(); for (int i = 0; i < array.length; i++) { @@ -562,6 +603,7 @@ public class ArrayUtil extends ArrayUtilRt { } @NotNull + @Contract(pure=true) public static int[] reverseArray(@NotNull int[] array) { int[] newArray = array.clone(); for (int i = 0; i < array.length; i++) { @@ -576,6 +618,7 @@ public class ArrayUtil extends ArrayUtilRt { } } + @Contract(pure=true) public static int lexicographicCompare(@NotNull String[] obj1, @NotNull String[] obj2) { for (int i = 0; i < Math.max(obj1.length, obj2.length); i++) { String o1 = i < obj1.length ? obj1[i] : null; @@ -589,6 +632,7 @@ public class ArrayUtil extends ArrayUtilRt { } //must be Comparables + @Contract(pure=true) public static <T> int lexicographicCompare(@NotNull T[] obj1, @NotNull T[] obj2) { for (int i = 0; i < Math.max(obj1.length, obj2.length); i++) { T o1 = i < obj1.length ? obj1[i] : null; @@ -637,10 +681,12 @@ public class ArrayUtil extends ArrayUtilRt { array[i1] = t; } + @Contract(pure=true) public static int indexOf(@NotNull Object[] objects, @Nullable Object object) { return indexOf(objects, object, 0, objects.length); } + @Contract(pure=true) public static int indexOf(@NotNull Object[] objects, Object object, int start, int end) { if (object == null) { for (int i = start; i < end; i++) { @@ -655,6 +701,7 @@ public class ArrayUtil extends ArrayUtilRt { return -1; } + @Contract(pure=true) public static <T> int indexOf(@NotNull List<T> objects, T object, @NotNull Equality<T> comparator) { for (int i = 0; i < objects.size(); i++) { if (comparator.equals(objects.get(i), object)) return i; @@ -662,6 +709,7 @@ public class ArrayUtil extends ArrayUtilRt { return -1; } + @Contract(pure=true) public static <T> int indexOf(@NotNull List<T> objects, T object, @NotNull Comparator<T> comparator) { for (int i = 0; i < objects.size(); i++) { if (comparator.compare(objects.get(i), object) == 0) return i; @@ -669,6 +717,7 @@ public class ArrayUtil extends ArrayUtilRt { return -1; } + @Contract(pure=true) public static <T> int indexOf(@NotNull T[] objects, T object, @NotNull Equality<T> comparator) { for (int i = 0; i < objects.length; i++) { if (comparator.equals(objects[i], object)) return i; @@ -676,6 +725,7 @@ public class ArrayUtil extends ArrayUtilRt { return -1; } + @Contract(pure=true) public static int indexOf(@NotNull int[] ints, int value) { for (int i = 0; i < ints.length; i++) { if (ints[i] == value) return i; @@ -683,6 +733,7 @@ public class ArrayUtil extends ArrayUtilRt { return -1; } + @Contract(pure=true) public static int indexOf(@NotNull short[] ints, short value) { for (int i = 0; i < ints.length; i++) { if (ints[i] == value) return i; @@ -691,10 +742,12 @@ public class ArrayUtil extends ArrayUtilRt { return -1; } + @Contract(pure=true) public static boolean contains(@Nullable final Object o, @NotNull Object... objects) { return indexOf(objects, o) >= 0; } + @Contract(pure=true) public static boolean contains(@Nullable final String s, @NotNull String... strings) { if (s == null) { for (String str : strings) { @@ -711,26 +764,31 @@ public class ArrayUtil extends ArrayUtilRt { } @NotNull + @Contract(pure=true) public static int[] newIntArray(int count) { return count == 0 ? EMPTY_INT_ARRAY : new int[count]; } @NotNull + @Contract(pure=true) public static long[] newLongArray(int count) { return count == 0 ? EMPTY_LONG_ARRAY : new long[count]; } @NotNull + @Contract(pure=true) public static String[] newStringArray(int count) { return count == 0 ? EMPTY_STRING_ARRAY : new String[count]; } @NotNull + @Contract(pure=true) public static Object[] newObjectArray(int count) { return count == 0 ? EMPTY_OBJECT_ARRAY : new Object[count]; } @NotNull + @Contract(pure=true) public static <E> E[] ensureExactSize(int count, @NotNull E[] sample) { if (count == sample.length) return sample; @SuppressWarnings({"unchecked"}) final E[] array = (E[])Array.newInstance(sample.getClass().getComponentType(), count); @@ -738,16 +796,19 @@ public class ArrayUtil extends ArrayUtilRt { } @Nullable + @Contract(pure=true) public static <T> T getFirstElement(@NotNull T[] array) { return array.length > 0 ? array[0] : null; } @Nullable + @Contract(pure=true) public static <T> T getLastElement(@NotNull T[] array) { return array.length > 0 ? array[array.length - 1] : null; } @NotNull + @Contract(pure=true) public static String[] toStringArray(@Nullable Collection<String> collection) { return ArrayUtilRt.toStringArray(collection); } diff --git a/platform/util/src/com/intellij/util/ReflectionUtil.java b/platform/util/src/com/intellij/util/ReflectionUtil.java index d5f6a58dc951..8e2204415988 100644 --- a/platform/util/src/com/intellij/util/ReflectionUtil.java +++ b/platform/util/src/com/intellij/util/ReflectionUtil.java @@ -19,17 +19,15 @@ package com.intellij.util; import com.intellij.Patches; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Condition; -import com.intellij.util.containers.ContainerUtil; +import com.intellij.openapi.util.DifferenceFilter; +import com.intellij.util.containers.*; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import sun.reflect.ConstructorAccessor; import java.lang.reflect.*; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; +import java.util.*; public class ReflectionUtil { private static final Logger LOG = Logger.getInstance("#com.intellij.util.ReflectionUtil"); @@ -479,6 +477,50 @@ public class ReflectionUtil { return callerClass; } + public static void copyFields(@NotNull Field[] fields, @NotNull Object from, @NotNull Object to) { + copyFields(fields, from, to, null); + } + + public static boolean copyFields(@NotNull Field[] fields, @NotNull Object from, @NotNull Object to, @Nullable DifferenceFilter diffFilter) { + Set<Field> sourceFields = new com.intellij.util.containers.HashSet<Field>(Arrays.asList(from.getClass().getFields())); + boolean valuesChanged = false; + for (Field field : fields) { + if (sourceFields.contains(field)) { + if (isPublic(field) && !isFinal(field)) { + try { + if (diffFilter == null || diffFilter.isAccept(field)) { + copyFieldValue(from, to, field); + valuesChanged = true; + } + } + catch (Exception e) { + throw new RuntimeException(e); + } + } + } + } + return valuesChanged; + } + + public static void copyFieldValue(@NotNull Object from, @NotNull Object to, @NotNull Field field) + throws IllegalAccessException { + Class<?> fieldType = field.getType(); + if (fieldType.isPrimitive() || fieldType.equals(String.class)) { + field.set(to, field.get(from)); + } + else { + throw new RuntimeException("Field '" + field.getName()+"' not copied: unsupported type: "+field.getType()); + } + } + + private static boolean isPublic(final Field field) { + return (field.getModifiers() & Modifier.PUBLIC) != 0; + } + + private static boolean isFinal(final Field field) { + return (field.getModifiers() & Modifier.FINAL) != 0; + } + private static class MySecurityManager extends SecurityManager { private static final MySecurityManager INSTANCE = new MySecurityManager(); diff --git a/platform/util/src/com/intellij/util/Restarter.java b/platform/util/src/com/intellij/util/Restarter.java index 01e7fc494f5b..1eb1691808be 100644 --- a/platform/util/src/com/intellij/util/Restarter.java +++ b/platform/util/src/com/intellij/util/Restarter.java @@ -153,11 +153,16 @@ public class Restarter { } public static File createTempExecutable(File executable) throws IOException { - File copy = new File(System.getProperty("user.home") + "/." + System.getProperty("idea.paths.selector") + "/restart/" + executable.getName()); - if (FileUtilRt.ensureCanCreateFile(copy)) { - FileUtilRt.copy(executable, copy); - if (!copy.setExecutable(executable.canExecute())) throw new IOException("Cannot make file executable: " + copy); + File executableDir = new File(System.getProperty("user.home") + "/." + System.getProperty("idea.paths.selector") + "/restart"); + File copy = new File(executableDir.getPath() + "/" + executable.getName()); + if (!FileUtilRt.ensureCanCreateFile(copy)) { + String ext = FileUtilRt.getExtension(executable.getName()); + copy = FileUtilRt.createTempFile(executableDir, FileUtilRt.getNameWithoutExtension(copy.getName()), + StringUtil.isEmptyOrSpaces(ext) ? ".tmp" : ("." + ext), + true, false); } + FileUtilRt.copy(executable, copy); + if (!copy.setExecutable(executable.canExecute())) throw new IOException("Cannot make file executable: " + copy); return copy; } diff --git a/platform/util/src/com/intellij/util/containers/ContainerUtil.java b/platform/util/src/com/intellij/util/containers/ContainerUtil.java index 40bd75a2eff8..0047217285a5 100644 --- a/platform/util/src/com/intellij/util/containers/ContainerUtil.java +++ b/platform/util/src/com/intellij/util/containers/ContainerUtil.java @@ -33,135 +33,166 @@ import java.util.LinkedHashSet; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.CopyOnWriteArrayList; -@SuppressWarnings({"UtilityClassWithoutPrivateConstructor", "MethodOverridesStaticMethodOfSuperclass", "UnusedDeclaration"}) +@SuppressWarnings({"UtilityClassWithoutPrivateConstructor", "MethodOverridesStaticMethodOfSuperclass"}) public class ContainerUtil extends ContainerUtilRt { private static final int INSERTION_SORT_THRESHOLD = 10; private static final int DEFAULT_CONCURRENCY_LEVEL = Math.min(16, Runtime.getRuntime().availableProcessors()); @NotNull + @Contract(pure=true) public static <T> T[] ar(@NotNull T... elements) { return elements; } @NotNull + @Contract(pure=true) public static <K, V> HashMap<K, V> newHashMap() { return ContainerUtilRt.newHashMap(); } @NotNull + @Contract(pure=true) public static <K, V> HashMap<K, V> newHashMap(@NotNull Map<K, V> map) { return ContainerUtilRt.newHashMap(map); } @NotNull + @Contract(pure=true) public static <K, V> Map<K, V> newHashMap(@NotNull Pair<K, V> first, Pair<K, V>... entries) { return ContainerUtilRt.newHashMap(first, entries); } @NotNull + @Contract(pure=true) public static <K, V> Map<K, V> newHashMap(@NotNull List<K> keys, @NotNull List<V> values) { return ContainerUtilRt.newHashMap(keys, values); } @NotNull + @Contract(pure=true) public static <K extends Comparable, V> TreeMap<K, V> newTreeMap() { return ContainerUtilRt.newTreeMap(); } @NotNull + @Contract(pure=true) public static <K extends Comparable, V> TreeMap<K, V> newTreeMap(@NotNull Map<K, V> map) { return ContainerUtilRt.newTreeMap(map); } @NotNull + @Contract(pure=true) public static <K, V> LinkedHashMap<K, V> newLinkedHashMap() { return ContainerUtilRt.newLinkedHashMap(); } @NotNull + @Contract(pure=true) + public static <K, V> LinkedHashMap<K, V> newLinkedHashMap(int capacity) { + return ContainerUtilRt.newLinkedHashMap(capacity); + } + + @NotNull + @Contract(pure=true) public static <K, V> LinkedHashMap<K, V> newLinkedHashMap(@NotNull Map<K, V> map) { return ContainerUtilRt.newLinkedHashMap(map); } @NotNull + @Contract(pure=true) public static <K, V> LinkedHashMap<K, V> newLinkedHashMap(@NotNull Pair<K, V> first, Pair<K, V>... entries) { return ContainerUtilRt.newLinkedHashMap(first, entries); } @NotNull + @Contract(pure=true) public static <K, V> THashMap<K, V> newTroveMap() { return new THashMap<K, V>(); } @NotNull + @Contract(pure=true) public static <K, V> THashMap<K, V> newTroveMap(@NotNull TObjectHashingStrategy<K> strategy) { return new THashMap<K, V>(strategy); } @NotNull + @Contract(pure=true) public static <K extends Enum<K>, V> EnumMap<K, V> newEnumMap(@NotNull Class<K> keyType) { return new EnumMap<K, V>(keyType); } @SuppressWarnings("unchecked") @NotNull + @Contract(pure=true) public static <T> TObjectHashingStrategy<T> canonicalStrategy() { return TObjectHashingStrategy.CANONICAL; } @SuppressWarnings("unchecked") @NotNull + @Contract(pure=true) public static <T> TObjectHashingStrategy<T> identityStrategy() { return TObjectHashingStrategy.IDENTITY; } @NotNull + @Contract(pure=true) public static <K, V> IdentityHashMap<K, V> newIdentityHashMap() { return new IdentityHashMap<K, V>(); } @NotNull + @Contract(pure=true) public static <T> LinkedList<T> newLinkedList() { return ContainerUtilRt.newLinkedList(); } @NotNull + @Contract(pure=true) public static <T> LinkedList<T> newLinkedList(@NotNull T... elements) { return ContainerUtilRt.newLinkedList(elements); } @NotNull + @Contract(pure=true) public static <T> LinkedList<T> newLinkedList(@NotNull Iterable<? extends T> elements) { return ContainerUtilRt.newLinkedList(elements); } @NotNull + @Contract(pure=true) public static <T> ArrayList<T> newArrayList() { return ContainerUtilRt.newArrayList(); } @NotNull + @Contract(pure=true) public static <E> ArrayList<E> newArrayList(@NotNull E... array) { return ContainerUtilRt.newArrayList(array); } @NotNull + @Contract(pure=true) public static <E> ArrayList<E> newArrayList(@NotNull Iterable<? extends E> iterable) { return ContainerUtilRt.newArrayList(iterable); } /** @deprecated Use {@link #newArrayListWithCapacity(int)} (to remove in IDEA 15) */ @SuppressWarnings("deprecation") + @Contract(pure=true) public static <T> ArrayList<T> newArrayListWithExpectedSize(int size) { return ContainerUtilRt.newArrayListWithCapacity(size); } @NotNull + @Contract(pure=true) public static <T> ArrayList<T> newArrayListWithCapacity(int size) { return ContainerUtilRt.newArrayListWithCapacity(size); } @NotNull + @Contract(pure=true) public static <T> List<T> newArrayList(@NotNull final T[] elements, final int start, final int end) { if (start < 0 || start > end || end > elements.length) { throw new IllegalArgumentException("start:" + start + " end:" + end + " length:" + elements.length); @@ -184,31 +215,37 @@ public class ContainerUtil extends ContainerUtilRt { } @NotNull + @Contract(pure=true) public static <T> List<T> newSmartList(T element) { return new SmartList<T>(element); } @NotNull + @Contract(pure=true) public static <T> List<T> newSmartList(@NotNull T... elements) { return new SmartList<T>(elements); } @NotNull + @Contract(pure=true) public static <T> HashSet<T> newHashSet() { return ContainerUtilRt.newHashSet(); } @NotNull + @Contract(pure=true) public static <T> HashSet<T> newHashSet(int initialCapacity) { return ContainerUtilRt.newHashSet(initialCapacity); } @NotNull + @Contract(pure=true) public static <T> HashSet<T> newHashSet(@NotNull T... elements) { return ContainerUtilRt.newHashSet(elements); } @NotNull + @Contract(pure=true) public static <T> HashSet<T> newHashSet(@NotNull Iterable<? extends T> iterable) { return ContainerUtilRt.newHashSet(iterable); } @@ -219,117 +256,141 @@ public class ContainerUtil extends ContainerUtilRt { } @NotNull + @Contract(pure=true) public static <T> Set<T> newHashOrEmptySet(@Nullable Iterable<? extends T> iterable) { boolean empty = iterable == null || iterable instanceof Collection && ((Collection)iterable).isEmpty(); return empty ? Collections.<T>emptySet() : ContainerUtilRt.newHashSet(iterable); } @NotNull + @Contract(pure=true) public static <T> LinkedHashSet<T> newLinkedHashSet() { return ContainerUtilRt.newLinkedHashSet(); } @NotNull + @Contract(pure=true) public static <T> LinkedHashSet<T> newLinkedHashSet(@NotNull Iterable<? extends T> elements) { return ContainerUtilRt.newLinkedHashSet(elements); } @NotNull + @Contract(pure=true) public static <T> LinkedHashSet<T> newLinkedHashSet(@NotNull T... elements) { return ContainerUtilRt.newLinkedHashSet(elements); } @NotNull + @Contract(pure=true) public static <T> THashSet<T> newTroveSet() { return new THashSet<T>(); } @NotNull + @Contract(pure=true) public static <T> THashSet<T> newTroveSet(@NotNull TObjectHashingStrategy<T> strategy) { return new THashSet<T>(strategy); } @NotNull + @Contract(pure=true) public static <T> THashSet<T> newTroveSet(@NotNull T... elements) { return newTroveSet(Arrays.asList(elements)); } @NotNull + @Contract(pure=true) public static <T> THashSet<T> newTroveSet(@NotNull TObjectHashingStrategy<T> strategy, @NotNull T... elements) { return new THashSet<T>(Arrays.asList(elements), strategy); } @NotNull + @Contract(pure=true) public static <T> THashSet<T> newTroveSet(@NotNull TObjectHashingStrategy<T> strategy, @NotNull Collection<T> elements) { return new THashSet<T>(elements, strategy); } @NotNull + @Contract(pure=true) public static <T> THashSet<T> newTroveSet(@NotNull Collection<T> elements) { return new THashSet<T>(elements); } @NotNull + @Contract(pure=true) public static <K> THashSet<K> newIdentityTroveSet() { return new THashSet<K>(ContainerUtil.<K>identityStrategy()); } @NotNull + @Contract(pure=true) public static <K> THashSet<K> newIdentityTroveSet(int initialCapacity) { return new THashSet<K>(initialCapacity, ContainerUtil.<K>identityStrategy()); } @NotNull + @Contract(pure=true) public static <K> THashSet<K> newIdentityTroveSet(@NotNull Collection<K> collection) { return new THashSet<K>(collection, ContainerUtil.<K>identityStrategy()); } @NotNull + @Contract(pure=true) public static <K,V> THashMap<K,V> newIdentityTroveMap() { return new THashMap<K,V>(ContainerUtil.<K>identityStrategy()); } @NotNull + @Contract(pure=true) public static <T> TreeSet<T> newTreeSet() { return ContainerUtilRt.newTreeSet(); } @NotNull + @Contract(pure=true) public static <T> TreeSet<T> newTreeSet(@NotNull Iterable<? extends T> elements) { return ContainerUtilRt.newTreeSet(elements); } @NotNull + @Contract(pure=true) public static <T> TreeSet<T> newTreeSet(@NotNull T... elements) { return ContainerUtilRt.newTreeSet(elements); } @NotNull + @Contract(pure=true) public static <T> TreeSet<T> newTreeSet(@Nullable Comparator<? super T> comparator) { return ContainerUtilRt.newTreeSet(comparator); } @NotNull + @Contract(pure=true) public static <K, V> ConcurrentMap<K, V> newConcurrentMap() { return CHM_FACTORY.createMap(); } + @Contract(pure=true) public static <K, V> ConcurrentMap<K,V> newConcurrentMap(@NotNull TObjectHashingStrategy<K> hashStrategy) { return CHM_FACTORY.createMap(hashStrategy); } + @Contract(pure=true) public static <K, V> ConcurrentMap<K,V> newConcurrentMap(int initialCapacity) { return CHM_FACTORY.createMap(initialCapacity); } + @Contract(pure=true) public static <K, V> ConcurrentMap<K,V> newConcurrentMap(int initialCapacity, float loadFactor, int concurrencyLevel, @NotNull TObjectHashingStrategy<K> hashStrategy) { return CHM_FACTORY.createMap(initialCapacity, loadFactor, concurrencyLevel, hashStrategy); } + @Contract(pure=true) public static <K, V> ConcurrentMap<K,V> newConcurrentMap(int initialCapacity, float loadFactor, int concurrencyLevel) { return CHM_FACTORY.createMap(initialCapacity, loadFactor, concurrencyLevel); } @NotNull + @Contract(pure=true) public static <E> List<E> reverse(@NotNull final List<E> elements) { if (elements.isEmpty()) { return ContainerUtilRt.emptyList(); @@ -349,37 +410,43 @@ public class ContainerUtil extends ContainerUtilRt { } @NotNull + @Contract(pure=true) public static <K, V> Map<K, V> union(@NotNull Map<? extends K, ? extends V> map, @NotNull Map<? extends K, ? extends V> map2) { - THashMap<K, V> result = new THashMap<K, V>(map.size() + map2.size()); + Map<K, V> result = new THashMap<K, V>(map.size() + map2.size()); result.putAll(map); result.putAll(map2); return result; } @NotNull + @Contract(pure=true) public static <T> Set<T> union(@NotNull Set<T> set, @NotNull Set<T> set2) { - THashSet<T> result = new THashSet<T>(set.size() + set2.size()); + Set<T> result = new THashSet<T>(set.size() + set2.size()); result.addAll(set); result.addAll(set2); return result; } @NotNull + @Contract(pure=true) public static <E> Set<E> immutableSet(@NotNull E ... elements) { return Collections.unmodifiableSet(new THashSet<E>(Arrays.asList(elements))); } @NotNull + @Contract(pure=true) public static <E> ImmutableList<E> immutableList(@NotNull E ... array) { return new ImmutableListBackedByArray<E>(array); } @NotNull + @Contract(pure=true) public static <E> ImmutableList<E> immutableList(@NotNull List<E> list) { return new ImmutableListBackedByList<E>(list); } @NotNull + @Contract(pure=true) public static <K, V> ImmutableMapBuilder<K, V> immutableMapBuilder() { return new ImmutableMapBuilder<K, V>(); } @@ -392,6 +459,7 @@ public class ContainerUtil extends ContainerUtilRt { return this; } + @Contract(pure=true) public Map<K, V> build() { return Collections.unmodifiableMap(myMap); } @@ -434,6 +502,7 @@ public class ContainerUtil extends ContainerUtilRt { } @NotNull + @Contract(pure=true) public static <K, V> Map<K, V> intersection(@NotNull Map<K, V> map1, @NotNull Map<K, V> map2) { final Map<K, V> res = newHashMap(); final Set<K> keys = newHashSet(); @@ -450,6 +519,7 @@ public class ContainerUtil extends ContainerUtilRt { } @NotNull + @Contract(pure=true) public static <K, V> Map<K,Couple<V>> diff(@NotNull Map<K, V> map1, @NotNull Map<K, V> map2) { final Map<K, Couple<V>> res = newHashMap(); final Set<K> keys = newHashSet(); @@ -505,6 +575,7 @@ public class ContainerUtil extends ContainerUtilRt { } @NotNull + @Contract(pure=true) public static <T> List<T> mergeSortedLists(@NotNull List<T> list1, @NotNull List<T> list2, @NotNull Comparator<? super T> comparator, @@ -521,6 +592,7 @@ public class ContainerUtil extends ContainerUtilRt { } @NotNull + @Contract(pure=true) public static <T> List<T> mergeSortedArrays(@NotNull T[] list1, @NotNull T[] list2, @NotNull Comparator<? super T> comparator, boolean mergeEqualItems, @Nullable Processor<? super T> filter) { int index1 = 0; int index2 = 0; @@ -572,6 +644,7 @@ public class ContainerUtil extends ContainerUtilRt { } @NotNull + @Contract(pure=true) public static <T> List<T> subList(@NotNull List<T> list, int from) { return list.subList(from, list.size()); } @@ -658,16 +731,19 @@ public class ContainerUtil extends ContainerUtilRt { } @NotNull + @Contract(pure=true) public static <T> Iterator<T> emptyIterator() { return EmptyIterator.getInstance(); } @NotNull + @Contract(pure=true) public static <T> Iterable<T> emptyIterable() { return EmptyIterable.getInstance(); } @Nullable + @Contract(pure=true) public static <T> T find(@NotNull T[] array, @NotNull Condition<T> condition) { for (T element : array) { if (condition.value(element)) return element; @@ -714,11 +790,13 @@ public class ContainerUtil extends ContainerUtilRt { } @Nullable + @Contract(pure=true) public static <T, V extends T> V find(@NotNull Iterable<V> iterable, @NotNull Condition<T> condition) { return find(iterable.iterator(), condition); } @Nullable + @Contract(pure=true) public static <T> T find(@NotNull Iterable<? extends T> iterable, final T equalTo) { return find(iterable, new Condition<T>() { @Override @@ -738,11 +816,13 @@ public class ContainerUtil extends ContainerUtilRt { } @NotNull + @Contract(pure=true) public static <T, KEY, VALUE> Map<KEY, VALUE> map2Map(@NotNull T[] collection, @NotNull Function<T, Pair<KEY, VALUE>> mapper) { return map2Map(Arrays.asList(collection), mapper); } @NotNull + @Contract(pure=true) public static <T, KEY, VALUE> Map<KEY, VALUE> map2Map(@NotNull Collection<? extends T> collection, @NotNull Function<T, Pair<KEY, VALUE>> mapper) { final Map<KEY, VALUE> set = new THashMap<KEY, VALUE>(collection.size()); @@ -754,6 +834,7 @@ public class ContainerUtil extends ContainerUtilRt { } @NotNull + @Contract(pure=true) public static <KEY, VALUE> Map<KEY, VALUE> map2Map(@NotNull Collection<Pair<KEY, VALUE>> collection) { final Map<KEY, VALUE> result = new THashMap<KEY, VALUE>(collection.size()); for (Pair<KEY, VALUE> pair : collection) { @@ -763,21 +844,25 @@ public class ContainerUtil extends ContainerUtilRt { } @NotNull + @Contract(pure=true) public static <T> Object[] map2Array(@NotNull T[] array, @NotNull Function<T, Object> mapper) { return map2Array(array, Object.class, mapper); } @NotNull + @Contract(pure=true) public static <T> Object[] map2Array(@NotNull Collection<T> array, @NotNull Function<T, Object> mapper) { return map2Array(array, Object.class, mapper); } @NotNull + @Contract(pure=true) public static <T, V> V[] map2Array(@NotNull T[] array, @NotNull Class<? extends V> aClass, @NotNull Function<T, V> mapper) { return map2Array(Arrays.asList(array), aClass, mapper); } @NotNull + @Contract(pure=true) public static <T, V> V[] map2Array(@NotNull Collection<? extends T> collection, @NotNull Class<? extends V> aClass, @NotNull Function<T, V> mapper) { final List<V> list = map2List(collection, mapper); @SuppressWarnings("unchecked") V[] array = (V[])Array.newInstance(aClass, list.size()); @@ -785,16 +870,19 @@ public class ContainerUtil extends ContainerUtilRt { } @NotNull + @Contract(pure=true) public static <T, V> V[] map2Array(@NotNull Collection<? extends T> collection, @NotNull V[] to, @NotNull Function<T, V> mapper) { return map2List(collection, mapper).toArray(to); } @NotNull + @Contract(pure=true) public static <T> List<T> filter(@NotNull T[] collection, @NotNull Condition<? super T> condition) { return findAll(collection, condition); } @NotNull + @Contract(pure=true) public static int[] filter(@NotNull int[] collection, @NotNull TIntProcedure condition) { TIntArrayList result = new TIntArrayList(); for (int t : collection) { @@ -806,11 +894,13 @@ public class ContainerUtil extends ContainerUtilRt { } @NotNull + @Contract(pure=true) public static <T> List<T> filter(@NotNull Condition<? super T> condition, @NotNull T... collection) { return findAll(collection, condition); } @NotNull + @Contract(pure=true) public static <T> List<T> findAll(@NotNull T[] collection, @NotNull Condition<? super T> condition) { final List<T> result = new SmartList<T>(); for (T t : collection) { @@ -822,11 +912,13 @@ public class ContainerUtil extends ContainerUtilRt { } @NotNull + @Contract(pure=true) public static <T> List<T> filter(@NotNull Collection<? extends T> collection, @NotNull Condition<? super T> condition) { return findAll(collection, condition); } @NotNull + @Contract(pure=true) public static <T> List<T> findAll(@NotNull Collection<? extends T> collection, @NotNull Condition<? super T> condition) { if (collection.isEmpty()) return emptyList(); final List<T> result = new SmartList<T>(); @@ -839,16 +931,19 @@ public class ContainerUtil extends ContainerUtilRt { } @NotNull + @Contract(pure=true) public static <T> List<T> skipNulls(@NotNull Collection<? extends T> collection) { return findAll(collection, Condition.NOT_NULL); } @NotNull + @Contract(pure=true) public static <T, V> List<V> findAll(@NotNull T[] collection, @NotNull Class<V> instanceOf) { return findAll(Arrays.asList(collection), instanceOf); } @NotNull + @Contract(pure=true) public static <T, V> V[] findAllAsArray(@NotNull T[] collection, @NotNull Class<V> instanceOf) { List<V> list = findAll(Arrays.asList(collection), instanceOf); @SuppressWarnings("unchecked") V[] array = (V[])Array.newInstance(instanceOf, list.size()); @@ -856,6 +951,7 @@ public class ContainerUtil extends ContainerUtilRt { } @NotNull + @Contract(pure=true) public static <T, V> V[] findAllAsArray(@NotNull Collection<? extends T> collection, @NotNull Class<V> instanceOf) { List<V> list = findAll(collection, instanceOf); @SuppressWarnings("unchecked") V[] array = (V[])Array.newInstance(instanceOf, list.size()); @@ -863,6 +959,7 @@ public class ContainerUtil extends ContainerUtilRt { } @NotNull + @Contract(pure=true) public static <T> T[] findAllAsArray(@NotNull T[] collection, @NotNull Condition<? super T> instanceOf) { List<T> list = findAll(collection, instanceOf); @SuppressWarnings("unchecked") T[] array = (T[])Array.newInstance(collection.getClass().getComponentType(), list.size()); @@ -870,6 +967,7 @@ public class ContainerUtil extends ContainerUtilRt { } @NotNull + @Contract(pure=true) public static <T, V> List<V> findAll(@NotNull Collection<? extends T> collection, @NotNull Class<V> instanceOf) { final List<V> result = new SmartList<V>(); for (final T t : collection) { @@ -895,6 +993,7 @@ public class ContainerUtil extends ContainerUtilRt { } @NotNull + @Contract(pure=true) public static Map<String, String> stringMap(@NotNull final String... keyValues) { final Map<String, String> result = newHashMap(); for (int i = 0; i < keyValues.length - 1; i+=2) { @@ -905,11 +1004,13 @@ public class ContainerUtil extends ContainerUtilRt { } @NotNull + @Contract(pure=true) public static <T> Iterator<T> iterate(@NotNull T[] arrays) { return Arrays.asList(arrays).iterator(); } @NotNull + @Contract(pure=true) public static <T> Iterator<T> iterate(@NotNull final Enumeration<T> enumeration) { return new Iterator<T>() { @Override @@ -930,11 +1031,13 @@ public class ContainerUtil extends ContainerUtilRt { } @NotNull + @Contract(pure=true) public static <T> Iterable<T> iterate(@NotNull T[] arrays, @NotNull Condition<? super T> condition) { return iterate(Arrays.asList(arrays), condition); } @NotNull + @Contract(pure=true) public static <T> Iterable<T> iterate(@NotNull final Collection<? extends T> collection, @NotNull final Condition<? super T> condition) { if (collection.isEmpty()) return emptyIterable(); return new Iterable<T>() { @@ -977,6 +1080,7 @@ public class ContainerUtil extends ContainerUtilRt { } @NotNull + @Contract(pure=true) public static <T> Iterable<T> iterateBackward(@NotNull final List<? extends T> list) { return new Iterable<T>() { @Override @@ -1068,6 +1172,7 @@ public class ContainerUtil extends ContainerUtilRt { return modified; } + @Contract(pure=true) public static <T, U extends T> U findInstance(@NotNull Iterable<T> iterable, @NotNull Class<U> aClass) { return findInstance(iterable.iterator(), aClass); } @@ -1079,11 +1184,13 @@ public class ContainerUtil extends ContainerUtilRt { } @Nullable + @Contract(pure=true) public static <T, U extends T> U findInstance(@NotNull T[] array, @NotNull Class<U> aClass) { return findInstance(Arrays.asList(array), aClass); } @NotNull + @Contract(pure=true) public static <T, V> List<T> concat(@NotNull V[] array, @NotNull Function<V, Collection<? extends T>> fun) { return concat(Arrays.asList(array), fun); } @@ -1092,6 +1199,7 @@ public class ContainerUtil extends ContainerUtilRt { * @return read-only list consisting of the elements from the collections stored in list added together */ @NotNull + @Contract(pure=true) public static <T> List<T> concat(@NotNull Iterable<? extends Collection<T>> list) { List<T> result = new ArrayList<T>(); for (final Collection<T> ts : list) { @@ -1105,6 +1213,7 @@ public class ContainerUtil extends ContainerUtilRt { * @return read-only list consisting of the elements from specified list with some additional values */ @NotNull + @Contract(pure=true) public static <T> List<T> concat(boolean appendTail, @NotNull List<? extends T> list, T... values) { return appendTail ? concat(list, list(values)) : concat(list(values), list); } @@ -1113,6 +1222,7 @@ public class ContainerUtil extends ContainerUtilRt { * @return read-only list consisting of the two lists added together */ @NotNull + @Contract(pure=true) public static <T> List<T> concat(@NotNull final List<? extends T> list1, @NotNull final List<? extends T> list2) { if (list1.isEmpty() && list2.isEmpty()) { return Collections.emptyList(); @@ -1139,6 +1249,7 @@ public class ContainerUtil extends ContainerUtilRt { } @NotNull + @Contract(pure=true) public static <T> Iterable<T> concat(@NotNull final Iterable<? extends T>... iterables) { return new Iterable<T>() { @Override @@ -1155,16 +1266,19 @@ public class ContainerUtil extends ContainerUtilRt { } @NotNull + @Contract(pure=true) public static <T> Iterator<T> concatIterators(@NotNull Iterator<T>... iterators) { return new SequenceIterator<T>(iterators); } @NotNull + @Contract(pure=true) public static <T> Iterator<T> concatIterators(@NotNull Collection<Iterator<T>> iterators) { return new SequenceIterator<T>(iterators); } @NotNull + @Contract(pure=true) public static <T> Iterable<T> concat(@NotNull final T[]... iterables) { return new Iterable<T>() { @Override @@ -1184,6 +1298,7 @@ public class ContainerUtil extends ContainerUtilRt { * @return read-only list consisting of the lists added together */ @NotNull + @Contract(pure=true) public static <T> List<T> concat(@NotNull final List<? extends T>... lists) { int size = 0; for (List<? extends T> each : lists) { @@ -1215,6 +1330,7 @@ public class ContainerUtil extends ContainerUtilRt { * @return read-only list consisting of the lists added together */ @NotNull + @Contract(pure=true) public static <T> List<T> concat(@NotNull final List<List<? extends T>> lists) { @SuppressWarnings("unchecked") List<? extends T>[] array = lists.toArray(new List[lists.size()]); return concat(array); @@ -1224,6 +1340,7 @@ public class ContainerUtil extends ContainerUtilRt { * @return read-only list consisting of the lists (made by listGenerator) added together */ @NotNull + @Contract(pure=true) public static <T, V> List<T> concat(@NotNull Iterable<? extends V> list, @NotNull Function<V, Collection<? extends T>> listGenerator) { List<T> result = new ArrayList<T>(); for (final V v : list) { @@ -1232,6 +1349,7 @@ public class ContainerUtil extends ContainerUtilRt { return result.isEmpty() ? ContainerUtil.<T>emptyList() : result; } + @Contract(pure=true) public static <T> boolean intersects(@NotNull Collection<? extends T> collection1, @NotNull Collection<? extends T> collection2) { for (T t : collection1) { //noinspection SuspiciousMethodCalls @@ -1246,6 +1364,7 @@ public class ContainerUtil extends ContainerUtilRt { * @return read-only collection consisting of elements from both collections */ @NotNull + @Contract(pure=true) public static <T> Collection<T> intersection(@NotNull Collection<? extends T> collection1, @NotNull Collection<? extends T> collection2) { List<T> result = new ArrayList<T>(); for (T t : collection1) { @@ -1257,15 +1376,18 @@ public class ContainerUtil extends ContainerUtilRt { } @Nullable + @Contract(pure=true) public static <T> T getFirstItem(@Nullable Collection<T> items) { return getFirstItem(items, null); } @Nullable + @Contract(pure=true) public static <T> T getFirstItem(@Nullable List<T> items) { return items == null || items.isEmpty() ? null : items.get(0); } + @Contract(pure=true) public static <T> T getFirstItem(@Nullable final Collection<T> items, @Nullable final T def) { return items == null || items.isEmpty() ? def : items.iterator().next(); } @@ -1280,11 +1402,13 @@ public class ContainerUtil extends ContainerUtilRt { * @return new list with no more than <code>maxItems</code> first elements */ @NotNull + @Contract(pure=true) public static <T> List<T> getFirstItems(@NotNull final List<T> items, int maxItems) { return items.subList(0, Math.min(maxItems, items.size())); } @Nullable + @Contract(pure=true) public static <T> T iterateAndGetLastItem(@NotNull Iterable<T> items) { Iterator<T> itr = items.iterator(); T res = null; @@ -1296,11 +1420,13 @@ public class ContainerUtil extends ContainerUtilRt { } @Nullable + @Contract(pure=true) public static <T, L extends List<T>> T getLastItem(@NotNull L list, @Nullable T def) { return list.isEmpty() ? def : list.get(list.size() - 1); } @Nullable + @Contract(pure=true) public static <T, L extends List<T>> T getLastItem(@NotNull L list) { return getLastItem(list, null); } @@ -1309,6 +1435,7 @@ public class ContainerUtil extends ContainerUtilRt { * @return read-only collection consisting of elements from the 'from' collection which are absent from the 'what' collection */ @NotNull + @Contract(pure=true) public static <T> Collection<T> subtract(@NotNull Collection<T> from, @NotNull Collection<T> what) { final Set<T> set = newHashSet(from); set.removeAll(what); @@ -1316,16 +1443,19 @@ public class ContainerUtil extends ContainerUtilRt { } @NotNull + @Contract(pure=true) public static <T> T[] toArray(@Nullable Collection<T> c, @NotNull ArrayFactory<T> factory) { return c != null ? c.toArray(factory.create(c.size())) : factory.create(0); } @NotNull + @Contract(pure=true) public static <T> T[] toArray(@NotNull Collection<? extends T> c1, @NotNull Collection<? extends T> c2, @NotNull ArrayFactory<T> factory) { return ArrayUtil.mergeCollections(c1, c2, factory); } @NotNull + @Contract(pure=true) public static <T> T[] mergeCollectionsToArray(@NotNull Collection<? extends T> c1, @NotNull Collection<? extends T> c2, @NotNull ArrayFactory<T> factory) { return ArrayUtil.mergeCollections(c1, c2, factory); } @@ -1424,6 +1554,7 @@ public class ContainerUtil extends ContainerUtilRt { } @NotNull + @Contract(pure=true) public static <T> List<T> sorted(@NotNull Collection<T> list, @NotNull Comparator<T> comparator) { List<T> sorted = newArrayList(list); sort(sorted, comparator); @@ -1431,6 +1562,7 @@ public class ContainerUtil extends ContainerUtilRt { } @NotNull + @Contract(pure=true) public static <T extends Comparable<T>> List<T> sorted(@NotNull Collection<T> list) { return sorted(list, new Comparator<T>() { @Override @@ -1475,6 +1607,7 @@ public class ContainerUtil extends ContainerUtilRt { * @return read-only list consisting of the elements from the iterable converted by mapping */ @NotNull + @Contract(pure=true) public static <T,V> List<V> map(@NotNull Iterable<? extends T> iterable, @NotNull Function<T, V> mapping) { List<V> result = new ArrayList<V>(); for (T t : iterable) { @@ -1487,6 +1620,7 @@ public class ContainerUtil extends ContainerUtilRt { * @return read-only list consisting of the elements from the iterable converted by mapping */ @NotNull + @Contract(pure=true) public static <T,V> List<V> map(@NotNull Collection<? extends T> iterable, @NotNull Function<T, V> mapping) { if (iterable.isEmpty()) return emptyList(); List<V> result = new ArrayList<V>(iterable.size()); @@ -1500,6 +1634,7 @@ public class ContainerUtil extends ContainerUtilRt { * @return read-only list consisting of the elements from the array converted by mapping with nulls filtered out */ @NotNull + @Contract(pure=true) public static <T, V> List<V> mapNotNull(@NotNull T[] array, @NotNull Function<T, V> mapping) { return mapNotNull(Arrays.asList(array), mapping); } @@ -1508,6 +1643,7 @@ public class ContainerUtil extends ContainerUtilRt { * @return read-only list consisting of the elements from the array converted by mapping with nulls filtered out */ @NotNull + @Contract(pure=true) public static <T, V> V[] mapNotNull(@NotNull T[] array, @NotNull Function<T, V> mapping, @NotNull V[] emptyArray) { List<V> result = new ArrayList<V>(array.length); for (T t : array) { @@ -1527,6 +1663,7 @@ public class ContainerUtil extends ContainerUtilRt { * @return read-only list consisting of the elements from the iterable converted by mapping with nulls filtered out */ @NotNull + @Contract(pure=true) public static <T, V> List<V> mapNotNull(@NotNull Iterable<? extends T> iterable, @NotNull Function<T, V> mapping) { List<V> result = new ArrayList<V>(); for (T t : iterable) { @@ -1542,6 +1679,7 @@ public class ContainerUtil extends ContainerUtilRt { * @return read-only list consisting of the elements from the array converted by mapping with nulls filtered out */ @NotNull + @Contract(pure=true) public static <T, V> List<V> mapNotNull(@NotNull Collection<? extends T> iterable, @NotNull Function<T, V> mapping) { if (iterable.isEmpty()) { return emptyList(); @@ -1561,6 +1699,7 @@ public class ContainerUtil extends ContainerUtilRt { * @return read-only list consisting of the elements with nulls filtered out */ @NotNull + @Contract(pure=true) public static <T> List<T> packNullables(@NotNull T... elements) { List<T> list = new ArrayList<T>(); for (T element : elements) { @@ -1573,6 +1712,7 @@ public class ContainerUtil extends ContainerUtilRt { * @return read-only list consisting of the elements from the array converted by mapping */ @NotNull + @Contract(pure=true) public static <T, V> List<V> map(@NotNull T[] array, @NotNull Function<T, V> mapping) { List<V> result = new ArrayList<V>(array.length); for (T t : array) { @@ -1582,6 +1722,7 @@ public class ContainerUtil extends ContainerUtilRt { } @NotNull + @Contract(pure=true) public static <T, V> V[] map(@NotNull T[] arr, @NotNull Function<T, V> mapping, @NotNull V[] emptyArray) { if (arr.length==0) { assert emptyArray.length == 0 : "You must pass an empty array"; @@ -1596,6 +1737,7 @@ public class ContainerUtil extends ContainerUtilRt { } @NotNull + @Contract(pure=true) public static <T> Set<T> set(@NotNull T ... items) { return newHashSet(items); } @@ -1618,11 +1760,13 @@ public class ContainerUtil extends ContainerUtilRt { } @NotNull + @Contract(pure=true) public static <T> List<T> createMaybeSingletonList(@Nullable T element) { return element == null ? ContainerUtil.<T>emptyList() : Collections.singletonList(element); } @NotNull + @Contract(pure=true) public static <T> Set<T> createMaybeSingletonSet(@Nullable T element) { return element == null ? Collections.<T>emptySet() : Collections.singleton(element); } @@ -1645,15 +1789,18 @@ public class ContainerUtil extends ContainerUtilRt { } @NotNull + @Contract(pure=true) public static <T, V> V getOrElse(@NotNull Map<T, V> result, final T key, @NotNull V defValue) { V value = result.get(key); return value == null ? defValue : value; } + @Contract(pure=true) public static <T> boolean and(@NotNull T[] iterable, @NotNull Condition<T> condition) { return and(Arrays.asList(iterable), condition); } + @Contract(pure=true) public static <T> boolean and(@NotNull Iterable<T> iterable, @NotNull Condition<T> condition) { for (final T t : iterable) { if (!condition.value(t)) return false; @@ -1661,18 +1808,22 @@ public class ContainerUtil extends ContainerUtilRt { return true; } + @Contract(pure=true) public static <T> boolean exists(@NotNull T[] iterable, @NotNull Condition<T> condition) { return or(Arrays.asList(iterable), condition); } + @Contract(pure=true) public static <T> boolean exists(@NotNull Iterable<T> iterable, @NotNull Condition<T> condition) { return or(iterable, condition); } + @Contract(pure=true) public static <T> boolean or(@NotNull T[] iterable, @NotNull Condition<T> condition) { return or(Arrays.asList(iterable), condition); } + @Contract(pure=true) public static <T> boolean or(@NotNull Iterable<T> iterable, @NotNull Condition<T> condition) { for (final T t : iterable) { if (condition.value(t)) return true; @@ -1681,10 +1832,11 @@ public class ContainerUtil extends ContainerUtilRt { } @NotNull + @Contract(pure=true) public static <T> List<T> unfold(@Nullable T t, @NotNull NullableFunction<T, T> next) { if (t == null) return emptyList(); - final ArrayList<T> list = new ArrayList<T>(); + List<T> list = new ArrayList<T>(); while (t != null) { list.add(t); t = next.fun(t); @@ -1693,11 +1845,13 @@ public class ContainerUtil extends ContainerUtilRt { } @NotNull + @Contract(pure=true) public static <T> List<T> dropTail(@NotNull List<T> items) { return items.subList(0, items.size() - 1); } @NotNull + @Contract(pure=true) public static <T> List<T> list(@NotNull T... items) { return Arrays.asList(items); } @@ -1845,6 +1999,7 @@ public class ContainerUtil extends ContainerUtilRt { * @return read-only set consisting of the only element o */ @NotNull + @Contract(pure=true) public static <T> Set<T> singleton(final T o, @NotNull final TObjectHashingStrategy<T> strategy) { return new SingletonSet<T>(o, strategy); } @@ -1853,6 +2008,7 @@ public class ContainerUtil extends ContainerUtilRt { * @return read-only list consisting of the elements from all of the collections */ @NotNull + @Contract(pure=true) public static <E> List<E> flatten(@NotNull Collection<E>[] collections) { return flatten(Arrays.asList(collections)); } @@ -1861,6 +2017,7 @@ public class ContainerUtil extends ContainerUtilRt { * @return read-only list consisting of the elements from all of the collections */ @NotNull + @Contract(pure=true) public static <E> List<E> flatten(@NotNull Iterable<? extends Collection<E>> collections) { List<E> result = new ArrayList<E>(); for (Collection<E> list : collections) { @@ -1874,6 +2031,7 @@ public class ContainerUtil extends ContainerUtilRt { * @return read-only list consisting of the elements from all of the collections */ @NotNull + @Contract(pure=true) public static <E> List<E> flattenIterables(@NotNull Iterable<? extends Iterable<E>> collections) { List<E> result = new ArrayList<E>(); for (Iterable<E> list : collections) { @@ -1885,6 +2043,7 @@ public class ContainerUtil extends ContainerUtilRt { } @NotNull + @Contract(pure=true) public static <K,V> V[] convert(@NotNull K[] from, @NotNull V[] to, @NotNull Function<K,V> fun) { if (to.length < from.length) { @SuppressWarnings("unchecked") V[] array = (V[])Array.newInstance(to.getClass().getComponentType(), from.length); @@ -1896,6 +2055,7 @@ public class ContainerUtil extends ContainerUtilRt { return to; } + @Contract(pure=true) public static <T> boolean containsIdentity(@NotNull Iterable<T> list, T element) { for (T t : list) { if (t == element) { @@ -1905,6 +2065,7 @@ public class ContainerUtil extends ContainerUtilRt { return false; } + @Contract(pure=true) public static <T> int indexOfIdentity(@NotNull List<T> list, T element) { for (int i = 0, listSize = list.size(); i < listSize; i++) { if (list.get(i) == element) { @@ -1914,6 +2075,7 @@ public class ContainerUtil extends ContainerUtilRt { return -1; } + @Contract(pure=true) public static <T> boolean equalsIdentity(@NotNull List<T> list1, @NotNull List<T> list2) { int listSize = list1.size(); if (list2.size() != listSize) { @@ -1928,6 +2090,7 @@ public class ContainerUtil extends ContainerUtilRt { return true; } + @Contract(pure=true) public static <T> int indexOf(@NotNull List<T> list, @NotNull Condition<T> condition) { for (int i = 0, listSize = list.size(); i < listSize; i++) { T t = list.get(i); @@ -1938,6 +2101,7 @@ public class ContainerUtil extends ContainerUtilRt { return -1; } + @Contract(pure=true) public static <T> int indexOf(@NotNull List<T> list, @NotNull final T object) { return indexOf(list, new Condition<T>() { @Override @@ -1948,6 +2112,7 @@ public class ContainerUtil extends ContainerUtilRt { } @NotNull + @Contract(pure=true) public static <A,B> Map<B,A> reverseMap(@NotNull Map<A,B> map) { final Map<B,A> result = newHashMap(); for (Map.Entry<A, B> entry : map.entrySet()) { @@ -1956,6 +2121,7 @@ public class ContainerUtil extends ContainerUtilRt { return result; } + @Contract(pure=true) public static <T> boolean processRecursively(final T root, @NotNull PairProcessor<T, List<T>> processor) { final LinkedList<T> list = new LinkedList<T>(); list.add(root); @@ -1979,26 +2145,31 @@ public class ContainerUtil extends ContainerUtilRt { } @NotNull + @Contract(pure=true) public static <T> Stack<T> newStack() { return ContainerUtilRt.newStack(); } @NotNull + @Contract(pure=true) public static <T> Stack<T> newStack(@NotNull Collection<T> initial) { return ContainerUtilRt.newStack(initial); } @NotNull + @Contract(pure=true) public static <T> Stack<T> newStack(@NotNull T... initial) { return ContainerUtilRt.newStack(initial); } @NotNull + @Contract(pure=true) public static <T> List<T> emptyList() { return ContainerUtilRt.emptyList(); } @NotNull + @Contract(pure=true) public static <T> CopyOnWriteArrayList<T> createEmptyCOWList() { return ContainerUtilRt.createEmptyCOWList(); } @@ -2011,16 +2182,19 @@ public class ContainerUtil extends ContainerUtilRt { * - slower modification in highly contented case (which is the kind of situation you shouldn't use COWAL anyway) */ @NotNull + @Contract(pure=true) public static <T> List<T> createLockFreeCopyOnWriteList() { return createConcurrentList(); } @NotNull + @Contract(pure=true) public static <T> List<T> createLockFreeCopyOnWriteList(@NotNull Collection<? extends T> c) { return new LockFreeCopyOnWriteArrayList<T>(c); } @NotNull + @Contract(pure=true) public static <T> ConcurrentList<T> createConcurrentList() { return new LockFreeCopyOnWriteArrayList<T>(); } @@ -2034,31 +2208,37 @@ public class ContainerUtil extends ContainerUtilRt { } @NotNull + @Contract(pure=true) public static <T, V> List<V> map2List(@NotNull T[] array, @NotNull Function<T, V> mapper) { return ContainerUtilRt.map2List(array, mapper); } @NotNull + @Contract(pure=true) public static <T, V> List<V> map2List(@NotNull Collection<? extends T> collection, @NotNull Function<T, V> mapper) { return ContainerUtilRt.map2List(collection, mapper); } @NotNull + @Contract(pure=true) public static <T, V> Set<V> map2Set(@NotNull T[] collection, @NotNull Function<T, V> mapper) { return ContainerUtilRt.map2Set(collection, mapper); } @NotNull + @Contract(pure=true) public static <T, V> Set<V> map2Set(@NotNull Collection<? extends T> collection, @NotNull Function<T, V> mapper) { return ContainerUtilRt.map2Set(collection, mapper); } @NotNull + @Contract(pure=true) public static <T> T[] toArray(@NotNull List<T> collection, @NotNull T[] array) { return ContainerUtilRt.toArray(collection, array); } @NotNull + @Contract(pure=true) public static <T> T[] toArray(@NotNull Collection<T> c, @NotNull T[] sample) { return ContainerUtilRt.toArray(c, sample); } @@ -2075,6 +2255,7 @@ public class ContainerUtil extends ContainerUtilRt { } @NotNull + @Contract(pure=true) public static <T> Collection<T> toCollection(@NotNull Iterable<T> iterable) { return iterable instanceof Collection ? (Collection<T>)iterable : newArrayList(iterable); } @@ -2092,18 +2273,26 @@ public class ContainerUtil extends ContainerUtilRt { return result; } - @Contract("null -> true") + @Contract(value = "null -> true", pure = true) public static <T> boolean isEmpty(Collection<T> collection) { return collection == null || collection.isEmpty(); } @NotNull - public static <T, C extends Collection<T>> C notNullize(@Nullable C collection) { + @Contract(pure=true) + public static <T> List<T> notNullize(@Nullable List<T> list) { + return list == null ? ContainerUtilRt.<T>emptyList() : list; + } + + @NotNull + @Contract(pure=true) + public static <T> Set<T> notNullize(@Nullable Set<T> set) { //noinspection unchecked - return collection == null ? (C)ContainerUtilRt.emptyList() : collection; + return set == null ? Collections.<T>emptySet() : set; } @Nullable + @Contract(pure=true) public static <T, C extends Collection<T>> C nullize(@Nullable C collection) { return isEmpty(collection) ? null : collection; } @@ -2117,26 +2306,31 @@ public class ContainerUtil extends ContainerUtilRt { } private static final ConcurrentMapFactory V8_MAP_FACTORY = new ConcurrentMapFactory() { + @Override @NotNull public <T, V> ConcurrentMap<T, V> createMap() { return new ConcurrentHashMap<T,V>(); } + @Override @NotNull public <T, V> ConcurrentMap<T, V> createMap(int initialCapacity) { return new ConcurrentHashMap<T,V>(initialCapacity); } + @Override @NotNull public <T, V> ConcurrentMap<T, V> createMap(@NotNull TObjectHashingStrategy<T> hashStrategy) { return new ConcurrentHashMap<T,V>(hashStrategy); } + @Override @NotNull public <T, V> ConcurrentMap<T, V> createMap(int initialCapacity, float loadFactor, int concurrencyLevel) { return new ConcurrentHashMap<T,V>(initialCapacity, loadFactor, concurrencyLevel); } + @Override @NotNull public <T, V> ConcurrentMap<T, V> createMap(int initialCapacity, float loadFactor, int concurrencyLevel, @NotNull TObjectHashingStrategy<T> hashingStrategy) { return new ConcurrentHashMap<T,V>(initialCapacity, loadFactor, concurrencyLevel, hashingStrategy); @@ -2144,16 +2338,19 @@ public class ContainerUtil extends ContainerUtilRt { }; private static final ConcurrentMapFactory PLATFORM_MAP_FACTORY = new ConcurrentMapFactory() { + @Override @NotNull public <T, V> ConcurrentMap<T, V> createMap() { return createMap(16, 0.75f, DEFAULT_CONCURRENCY_LEVEL); } + @Override @NotNull public <T, V> ConcurrentMap<T, V> createMap(int initialCapacity) { return new java.util.concurrent.ConcurrentHashMap<T,V>(initialCapacity); } + @Override @NotNull public <T, V> ConcurrentMap<T, V> createMap(@NotNull TObjectHashingStrategy<T> hashingStrategy) { if (hashingStrategy != canonicalStrategy()) { @@ -2163,11 +2360,13 @@ public class ContainerUtil extends ContainerUtilRt { return createMap(); } + @Override @NotNull public <T, V> ConcurrentMap<T, V> createMap(int initialCapacity, float loadFactor, int concurrencyLevel) { return new java.util.concurrent.ConcurrentHashMap<T,V>(initialCapacity, loadFactor, concurrencyLevel); } + @Override @NotNull public <T, V> ConcurrentMap<T, V> createMap(int initialCapacity, float loadFactor, int concurrencyLevel, @NotNull TObjectHashingStrategy<T> hashingStrategy) { if (hashingStrategy != canonicalStrategy()) { @@ -2185,7 +2384,8 @@ public class ContainerUtil extends ContainerUtilRt { return StringUtil.compareVersionNumbers(SystemInfo.JAVA_VERSION, "1.7") >= 0; } - public static <T extends Comparable<T>> int compareLexicographically(List<T> o1, List<T> o2) { + @Contract(pure=true) + public static <T extends Comparable<T>> int compareLexicographically(@NotNull List<T> o1, @NotNull List<T> o2) { for (int i = 0; i < Math.min(o1.size(), o2.size()); i++) { int result = o1.get(i).compareTo(o2.get(i)); if (result != 0) { @@ -2194,5 +2394,16 @@ public class ContainerUtil extends ContainerUtilRt { } return o1.size() < o2.size() ? -1 : o1.size() == o2.size() ? 0 : 1; } + + @Contract(pure=true) + public static <T> int compareLexicographically(@NotNull List<T> o1, @NotNull List<T> o2, @NotNull Comparator<T> comparator) { + for (int i = 0; i < Math.min(o1.size(), o2.size()); i++) { + int result = comparator.compare(o1.get(i), o2.get(i)); + if (result != 0) { + return result; + } + } + return o1.size() < o2.size() ? -1 : o1.size() == o2.size() ? 0 : 1; + } } diff --git a/platform/util/src/com/intellij/util/containers/FactoryMap.java b/platform/util/src/com/intellij/util/containers/FactoryMap.java index 30684d0e6dfa..3eea4d3dd984 100644 --- a/platform/util/src/com/intellij/util/containers/FactoryMap.java +++ b/platform/util/src/com/intellij/util/containers/FactoryMap.java @@ -15,6 +15,7 @@ */ package com.intellij.util.containers; +import com.intellij.util.ObjectUtils; import gnu.trove.THashMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -92,7 +93,7 @@ public abstract class FactoryMap<K,V> implements Map<K, V> { public Collection<V> notNullValues() { if (myMap == null) return Collections.emptyList(); - final Collection<V> values = new ArrayList<V>(myMap.values()); + final Collection<V> values = ContainerUtil.newArrayList(myMap.values()); for (Iterator<V> iterator = values.iterator(); iterator.hasNext();) { if (iterator.next() == NULL) { iterator.remove(); @@ -101,6 +102,13 @@ public abstract class FactoryMap<K,V> implements Map<K, V> { return values; } + public boolean removeValue(Object value) { + if (myMap == null) return false; + Object t = ObjectUtils.notNull(value, NULL); + return myMap.values().remove(t); + } + + @Override public void clear() { if (myMap != null) { diff --git a/platform/util/src/com/intellij/util/containers/TransferToEDTQueue.java b/platform/util/src/com/intellij/util/containers/TransferToEDTQueue.java index 5db4de22b401..425947ba50cb 100644 --- a/platform/util/src/com/intellij/util/containers/TransferToEDTQueue.java +++ b/platform/util/src/com/intellij/util/containers/TransferToEDTQueue.java @@ -16,6 +16,7 @@ package com.intellij.util.containers; import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.Conditions; import com.intellij.util.Processor; import com.intellij.util.concurrency.Semaphore; import gnu.trove.Equality; @@ -80,7 +81,7 @@ public class TransferToEDTQueue<T> { runnable.run(); return true; } - }, Condition.FALSE, maxUnitOfWorkThresholdMs); + }, Conditions.alwaysFalse(), maxUnitOfWorkThresholdMs); } private boolean isEmpty() { diff --git a/platform/util/src/com/intellij/util/io/AppendableStorageBackedByResizableMappedFile.java b/platform/util/src/com/intellij/util/io/AppendableStorageBackedByResizableMappedFile.java index c4381da1a406..1c43b652b02b 100644 --- a/platform/util/src/com/intellij/util/io/AppendableStorageBackedByResizableMappedFile.java +++ b/platform/util/src/com/intellij/util/io/AppendableStorageBackedByResizableMappedFile.java @@ -72,8 +72,7 @@ public class AppendableStorageBackedByResizableMappedFile extends ResizeableMapp } public <Data> boolean processAll(Processor<Data> processor, KeyDescriptor<Data> descriptor) throws IOException { - force(); - + assert !isDirty(); DataInputStream keysStream = new DataInputStream(new BufferedInputStream(new LimitedInputStream(new FileInputStream(getPagedFileStorage().getFile()), myFileLength) { @Override diff --git a/platform/util/src/com/intellij/util/io/PersistentEnumeratorBase.java b/platform/util/src/com/intellij/util/io/PersistentEnumeratorBase.java index 9f879f67d99d..eb7cdef28d69 100644 --- a/platform/util/src/com/intellij/util/io/PersistentEnumeratorBase.java +++ b/platform/util/src/com/intellij/util/io/PersistentEnumeratorBase.java @@ -443,11 +443,13 @@ public abstract class PersistentEnumeratorBase<Data> implements Forceable, Close lockStorage(); // todo locking in key storage try { - return myKeyStorage.processAll(processor, myDataDescriptor); + myKeyStorage.force(); } finally { unlockStorage(); } + + return myKeyStorage.processAll(processor, myDataDescriptor); } private File keystreamFile() { diff --git a/platform/util/src/com/intellij/util/messages/impl/MessageListenerList.java b/platform/util/src/com/intellij/util/messages/impl/MessageListenerList.java index d054416846a1..6d7bf76ccde7 100644 --- a/platform/util/src/com/intellij/util/messages/impl/MessageListenerList.java +++ b/platform/util/src/com/intellij/util/messages/impl/MessageListenerList.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,14 +15,14 @@ */ package com.intellij.util.messages.impl; +import com.intellij.openapi.Disposable; +import com.intellij.openapi.util.Disposer; +import com.intellij.util.containers.ConcurrentHashMap; import com.intellij.util.messages.MessageBus; import com.intellij.util.messages.MessageBusConnection; import com.intellij.util.messages.Topic; -import com.intellij.openapi.Disposable; -import com.intellij.openapi.util.Disposer; import org.jetbrains.annotations.NotNull; -import java.util.HashMap; import java.util.Map; /** @@ -31,7 +31,7 @@ import java.util.Map; public class MessageListenerList<T> { private final MessageBus myMessageBus; private final Topic<T> myTopic; - private final Map<T, MessageBusConnection> myListenerToConnectionMap = new HashMap<T, MessageBusConnection>(); + private final Map<T, MessageBusConnection> myListenerToConnectionMap = new ConcurrentHashMap<T, MessageBusConnection>(); public MessageListenerList(@NotNull MessageBus messageBus, @NotNull Topic<T> topic) { myTopic = topic; diff --git a/platform/util/src/com/intellij/util/ui/JBSwingUtilities.java b/platform/util/src/com/intellij/util/ui/JBSwingUtilities.java new file mode 100644 index 000000000000..d48aa5fc4ad2 --- /dev/null +++ b/platform/util/src/com/intellij/util/ui/JBSwingUtilities.java @@ -0,0 +1,53 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.util.ui; + +import java.awt.event.InputEvent; +import java.awt.event.MouseEvent; + +/** + * @author gregsh + */ +public class JBSwingUtilities { + /** + * Replaces SwingUtilities#isLeftMouseButton() for consistency with other button-related methods + * + * @see javax.swing.SwingUtilities#isLeftMouseButton(java.awt.event.MouseEvent) + */ + public static boolean isLeftMouseButton(MouseEvent anEvent) { + return (anEvent.getModifiersEx() & InputEvent.BUTTON1_DOWN_MASK) > 0; + } + + /** + * Replaces SwingUtilities#isMiddleMouseButton() due to the fact that BUTTON2_MASK == Event.ALT_MASK + * + * @see javax.swing.SwingUtilities#isMiddleMouseButton(java.awt.event.MouseEvent) + * @see java.awt.event.InputEvent#BUTTON2_MASK + */ + public static boolean isMiddleMouseButton(MouseEvent anEvent) { + return (anEvent.getModifiersEx() & InputEvent.BUTTON2_DOWN_MASK) > 0; + } + + /** + * Replaces SwingUtilities#isRightMouseButton() due to the fact that BUTTON3_MASK == Event.META_MASK + * + * @see javax.swing.SwingUtilities#isRightMouseButton(java.awt.event.MouseEvent) + * @see java.awt.event.InputEvent#BUTTON3_MASK + */ + public static boolean isRightMouseButton(MouseEvent anEvent) { + return (anEvent.getModifiersEx() & InputEvent.BUTTON3_DOWN_MASK) > 0; + } +} diff --git a/platform/util/src/com/intellij/util/ui/UIUtil.java b/platform/util/src/com/intellij/util/ui/UIUtil.java index aec2a356ded0..28c95b80763c 100644 --- a/platform/util/src/com/intellij/util/ui/UIUtil.java +++ b/platform/util/src/com/intellij/util/ui/UIUtil.java @@ -2085,7 +2085,7 @@ public class UIUtil { * Invoke and wait in the event dispatch thread * or in the current thread if the current thread * is event queue thread. - * + * DO NOT INVOKE THIS METHOD FROM UNDER READ ACTION. * @param runnable a runnable to invoke * @see #invokeAndWaitIfNeeded(com.intellij.util.ThrowableRunnable) */ @@ -2103,6 +2103,14 @@ public class UIUtil { } } + /** + * Invoke and wait in the event dispatch thread + * or in the current thread if the current thread + * is event queue thread. + * DO NOT INVOKE THIS METHOD FROM UNDER READ ACTION. + * @param computable a runnable to invoke + * @see #invokeAndWaitIfNeeded(com.intellij.util.ThrowableRunnable) + */ public static <T> T invokeAndWaitIfNeeded(@NotNull final Computable<T> computable) { final Ref<T> result = Ref.create(); invokeAndWaitIfNeeded(new Runnable() { @@ -2114,6 +2122,14 @@ public class UIUtil { return result.get(); } + /** + * Invoke and wait in the event dispatch thread + * or in the current thread if the current thread + * is event queue thread. + * DO NOT INVOKE THIS METHOD FROM UNDER READ ACTION. + * @param runnable a runnable to invoke + * @see #invokeAndWaitIfNeeded(com.intellij.util.ThrowableRunnable) + */ public static void invokeAndWaitIfNeeded(@NotNull final ThrowableRunnable runnable) throws Throwable { if (SwingUtilities.isEventDispatchThread()) { runnable.run(); @@ -2890,6 +2906,7 @@ public class UIUtil { new Thread(new Runnable() { // The wrapper thread is unnecessary, unless it blocks on the // Clip finishing; see comments. + @Override public void run() { try { Clip clip = AudioSystem.getClip(); diff --git a/platform/util/src/com/intellij/util/ui/tree/WideSelectionTreeUI.java b/platform/util/src/com/intellij/util/ui/tree/WideSelectionTreeUI.java index ba0eb265655e..9775ddb01be1 100644 --- a/platform/util/src/com/intellij/util/ui/tree/WideSelectionTreeUI.java +++ b/platform/util/src/com/intellij/util/ui/tree/WideSelectionTreeUI.java @@ -16,6 +16,7 @@ package com.intellij.util.ui.tree; import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.Conditions; import com.intellij.openapi.util.SystemInfo; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NonNls; @@ -53,7 +54,7 @@ public class WideSelectionTreeUI extends BasicTreeUI { @SuppressWarnings("unchecked") public WideSelectionTreeUI() { - this(true, Condition.TRUE); + this(true, Conditions.<Integer>alwaysTrue()); } /** |